Merge "Fixed navigation bar to show itself after creating a new user through keyguard ui." into rvc-dev
diff --git a/Android.bp b/Android.bp
index 9c1a085..8adf48d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -546,7 +546,6 @@
         // DO NOT ADD ANY MORE ENTRIES TO THIS LIST
         "//external/robolectric-shadows:__subpackages__",
         "//frameworks/layoutlib:__subpackages__",
-        "//frameworks/opt/net/ike:__subpackages__",
     ],
 }
 
@@ -694,6 +693,7 @@
         "core/java/android/annotation/CallbackExecutor.java",
         "core/java/android/annotation/CheckResult.java",
         "core/java/android/annotation/CurrentTimeMillisLong.java",
+        "core/java/android/annotation/Hide.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/IntRange.java",
         "core/java/android/annotation/LongDef.java",
@@ -753,6 +753,18 @@
     ],
 }
 
+filegroup {
+    name: "framework-services-net-module-wifi-shared-srcs",
+    srcs: [
+        "core/java/android/net/DhcpResults.java",
+        "core/java/android/net/shared/Inet4AddressUtils.java",
+        "core/java/android/net/shared/InetAddressUtils.java",
+        "core/java/android/net/util/IpUtils.java",
+        "core/java/android/util/LocalLog.java",
+        "core/java/com/android/internal/util/Preconditions.java",
+    ],
+}
+
 // keep these files in sync with the package/Tethering/jarjar-rules.txt for the tethering module.
 filegroup {
     name: "framework-tethering-shared-srcs",
@@ -974,7 +986,6 @@
     srcs: [
         "core/java/android/os/incremental/IIncrementalService.aidl",
         "core/java/android/os/incremental/IncrementalNewFileParams.aidl",
-        "core/java/android/os/incremental/IncrementalSignature.aidl",
     ],
     path: "core/java",
 }
@@ -1241,7 +1252,6 @@
         "core/java/android/net/InterfaceConfiguration.java",
         "core/java/android/os/BasicShellCommandHandler.java",
         "core/java/android/util/BackupUtils.java",
-        "core/java/android/util/LocalLog.java",
         "core/java/android/util/Rational.java",
         "core/java/com/android/internal/util/FastXmlSerializer.java",
         "core/java/com/android/internal/util/HexDump.java",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 7f23df7..da9f165 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -41,7 +41,7 @@
 ]
 
 stubs_defaults {
-    name: "metalava-non-updatable-api-stubs-default",
+    name: "metalava-base-api-stubs-default",
     srcs: [
         ":framework-non-updatable-sources",
         "core/java/**/*.logtags",
@@ -70,12 +70,18 @@
 }
 
 stubs_defaults {
-    name: "metalava-api-stubs-default",
-    defaults: ["metalava-non-updatable-api-stubs-default"],
+    name: "metalava-full-api-stubs-default",
+    defaults: ["metalava-base-api-stubs-default"],
     srcs: [":framework-updatable-sources"],
     sdk_version: "core_platform",
 }
 
+stubs_defaults {
+    name: "metalava-non-updatable-api-stubs-default",
+    defaults: ["metalava-base-api-stubs-default"],
+    sdk_version: "system_current",
+}
+
 /////////////////////////////////////////////////////////////////////
 // *-api-stubs-docs modules providing source files for the stub libraries
 /////////////////////////////////////////////////////////////////////
@@ -85,7 +91,7 @@
 // modules
 droidstubs {
     name: "api-stubs-docs",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-full-api-stubs-default"],
     api_filename: "public_api.txt",
     private_api_filename: "private.txt",
     removed_api_filename: "removed.txt",
@@ -124,7 +130,7 @@
 
 droidstubs {
     name: "system-api-stubs-docs",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-full-api-stubs-default"],
     api_tag_name: "SYSTEM",
     api_filename: "system-api.txt",
     private_api_filename: "system-private.txt",
@@ -155,7 +161,7 @@
 
 droidstubs {
     name: "test-api-stubs-docs",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-full-api-stubs-default"],
     api_tag_name: "TEST",
     api_filename: "test-api.txt",
     removed_api_filename: "test-removed.txt",
@@ -188,7 +194,7 @@
 
 droidstubs {
     name: "module-lib-api",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-full-api-stubs-default"],
     arg_files: ["core/res/AndroidManifest.xml"],
     args: metalava_framework_docs_args + module_libs,
     check_api: {
@@ -216,7 +222,7 @@
 
 droidstubs {
     name: "module-lib-api-stubs-docs",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-non-updatable-api-stubs-default"],
     arg_files: ["core/res/AndroidManifest.xml"],
     args: metalava_framework_docs_args + priv_apps + module_libs,
 }
@@ -266,6 +272,7 @@
     name: "android_module_lib_stubs_current",
     srcs: [ ":module-lib-api-stubs-docs" ],
     defaults: ["framework-stubs-default"],
+    libs: ["android_system_stubs_current"],
 }
 
 /////////////////////////////////////////////////////////////////////
@@ -317,7 +324,7 @@
 
 droidstubs {
     name: "hiddenapi-lists-docs",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-full-api-stubs-default"],
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
@@ -332,7 +339,7 @@
 
 droidstubs {
     name: "hiddenapi-mappings",
-    defaults: ["metalava-api-stubs-default"],
+    defaults: ["metalava-full-api-stubs-default"],
     srcs: [
         ":opt-telephony-common-srcs",
     ],
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
index 02df5e2..23f025b 100644
--- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -121,8 +121,9 @@
     }
 
     private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
-        final DummyBlobData blobData = new DummyBlobData(mContext,
-                fileSizeInMb * 1024 * 1024 /* bytes */);
+        final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+                .setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
+                .build();
         blobData.prepare();
         return blobData;
     }
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index c458d11..e042782 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -670,7 +670,7 @@
     private void startApp(int userId, String packageName) throws RemoteException {
         final Context context = InstrumentationRegistry.getContext();
         final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
-                context.getPackageName(), context.getFeatureId(),
+                context.getPackageName(), context.getAttributionTag(),
                 context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
                 null, 0, 0, null, null, userId);
         attestTrue("User " + userId + " failed to start " + packageName,
diff --git a/apex/Android.bp b/apex/Android.bp
index 1510911..39137fb 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -49,7 +49,7 @@
 stubs_defaults {
     name: "framework-module-stubs-defaults-systemapi",
     args: mainline_stubs_args + priv_apps,
-    srcs: [":framework-annotations"],
+    libs: ["framework-annotations-lib"],
     installable: false,
     sdk_version: "system_current",
 }
@@ -62,7 +62,7 @@
 stubs_defaults {
     name: "framework-module-api-defaults-module_libs_api",
     args: mainline_stubs_args + module_libs,
-    srcs: [":framework-annotations"],
+    libs: ["framework-annotations-lib"],
     installable: false,
     sdk_version: "module_current",
 }
@@ -70,7 +70,7 @@
 stubs_defaults {
     name: "framework-module-stubs-defaults-module_libs_api",
     args: mainline_stubs_args + module_libs + priv_apps,
-    srcs: [":framework-annotations"],
+    libs: ["framework-annotations-lib"],
     installable: false,
     sdk_version: "module_current",
 }
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
index 9746dd0..80062d5 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
@@ -32,21 +32,21 @@
     private final long mId;
     private final long mExpiryTimeMs;
     private final CharSequence mLabel;
-    private final List<AccessorInfo> mAccessors;
+    private final List<LeaseInfo> mLeaseInfos;
 
     public BlobInfo(long id, long expiryTimeMs, CharSequence label,
-            List<AccessorInfo> accessors) {
+            List<LeaseInfo> leaseInfos) {
         mId = id;
         mExpiryTimeMs = expiryTimeMs;
         mLabel = label;
-        mAccessors = accessors;
+        mLeaseInfos = leaseInfos;
     }
 
     private BlobInfo(Parcel in) {
         mId = in.readLong();
         mExpiryTimeMs = in.readLong();
         mLabel = in.readCharSequence();
-        mAccessors = in.readArrayList(null /* classloader */);
+        mLeaseInfos = in.readArrayList(null /* classloader */);
     }
 
     public long getId() {
@@ -61,8 +61,8 @@
         return mLabel;
     }
 
-    public List<AccessorInfo> getAccessors() {
-        return Collections.unmodifiableList(mAccessors);
+    public List<LeaseInfo> getLeases() {
+        return Collections.unmodifiableList(mLeaseInfos);
     }
 
     @Override
@@ -70,7 +70,7 @@
         dest.writeLong(mId);
         dest.writeLong(mExpiryTimeMs);
         dest.writeCharSequence(mLabel);
-        dest.writeList(mAccessors);
+        dest.writeList(mLeaseInfos);
     }
 
     @Override
@@ -83,7 +83,7 @@
                 + "id: " + mId + ","
                 + "expiryMs: " + mExpiryTimeMs + ","
                 + "label: " + mLabel + ","
-                + "accessors: " + AccessorInfo.toShortString(mAccessors) + ","
+                + "leases: " + LeaseInfo.toShortString(mLeaseInfos) + ","
                 + "}";
     }
 
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index 814ab6d..c339351 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -21,6 +21,7 @@
 import android.annotation.IdRes;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.content.Context;
@@ -522,6 +523,50 @@
     }
 
     /**
+     * Return the {@link BlobHandle BlobHandles} corresponding to the data blobs that
+     * the calling app has acquired a lease on using {@link #acquireLease(BlobHandle, int)} or
+     * one of it's other variants.
+     *
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public List<BlobHandle> getLeasedBlobs() throws IOException {
+        try {
+            return mService.getLeasedBlobs(mContext.getOpPackageName());
+        } catch (ParcelableException e) {
+            e.maybeRethrow(IOException.class);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return {@link LeaseInfo} representing a lease acquired using
+     * {@link #acquireLease(BlobHandle, int)} or one of it's other variants,
+     * or {@code null} if there is no lease acquired.
+     *
+     * @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.
+     *
+     * @hide
+     */
+    @TestApi
+    @Nullable
+    public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle) throws IOException {
+        try {
+            return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName());
+        } 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.
      *
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
index e783813..20c15ab 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
@@ -18,6 +18,7 @@
 import android.app.blob.BlobHandle;
 import android.app.blob.BlobInfo;
 import android.app.blob.IBlobStoreSession;
+import android.app.blob.LeaseInfo;
 import android.os.RemoteCallback;
 
 /** {@hide} */
@@ -35,4 +36,7 @@
 
     List<BlobInfo> queryBlobsForUser(int userId);
     void deleteBlob(long blobId);
+
+    List<BlobHandle> getLeasedBlobs(in String packageName);
+    LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName);
 }
\ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl
new file mode 100644
index 0000000..9088857
--- /dev/null
+++ b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/** {@hide} */
+parcelable LeaseInfo;
\ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.java
similarity index 61%
rename from apex/blobstore/framework/java/android/app/blob/AccessorInfo.java
rename to apex/blobstore/framework/java/android/app/blob/LeaseInfo.java
index 3725ad4..fef50c9 100644
--- a/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java
+++ b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.java
@@ -16,50 +16,61 @@
 
 package android.app.blob;
 
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.IdRes;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.util.List;
 
 /**
- * Class to provide information about an accessor of a shared blob.
+ * Class to provide information about a lease (acquired using
+ * {@link BlobStoreManager#acquireLease(BlobHandle, int)} or one of it's variants)
+ * for a shared blob.
  *
  * @hide
  */
-public final class AccessorInfo implements Parcelable {
+@TestApi
+public final class LeaseInfo implements Parcelable {
     private final String mPackageName;
-    private final long mExpiryTimeMs;
+    private final long mExpiryTimeMillis;
     private final int mDescriptionResId;
     private final CharSequence mDescription;
 
-    public AccessorInfo(String packageName, long expiryTimeMs,
-            int descriptionResId, CharSequence description) {
+    public LeaseInfo(@NonNull String packageName, @CurrentTimeMillisLong long expiryTimeMs,
+            @IdRes int descriptionResId, @Nullable CharSequence description) {
         mPackageName = packageName;
-        mExpiryTimeMs = expiryTimeMs;
+        mExpiryTimeMillis = expiryTimeMs;
         mDescriptionResId = descriptionResId;
         mDescription = description;
     }
 
-    private AccessorInfo(Parcel in) {
+    private LeaseInfo(Parcel in) {
         mPackageName = in.readString();
-        mExpiryTimeMs = in.readLong();
+        mExpiryTimeMillis = in.readLong();
         mDescriptionResId = in.readInt();
         mDescription = in.readCharSequence();
     }
 
+    @NonNull
     public String getPackageName() {
         return mPackageName;
     }
 
-    public long getExpiryTimeMs() {
-        return mExpiryTimeMs;
+    @CurrentTimeMillisLong
+    public long getExpiryTimeMillis() {
+        return mExpiryTimeMillis;
     }
 
+    @IdRes
     public int getDescriptionResId() {
         return mDescriptionResId;
     }
 
+    @Nullable
     public CharSequence getDescription() {
         return mDescription;
     }
@@ -67,16 +78,16 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mPackageName);
-        dest.writeLong(mExpiryTimeMs);
+        dest.writeLong(mExpiryTimeMillis);
         dest.writeInt(mDescriptionResId);
         dest.writeCharSequence(mDescription);
     }
 
     @Override
     public String toString() {
-        return "AccessorInfo {"
+        return "LeaseInfo {"
                 + "package: " + mPackageName + ","
-                + "expiryMs: " + mExpiryTimeMs + ","
+                + "expiryMs: " + mExpiryTimeMillis + ","
                 + "descriptionResId: " + mDescriptionResId + ","
                 + "description: " + mDescription + ","
                 + "}";
@@ -86,11 +97,11 @@
         return mPackageName;
     }
 
-    public static String toShortString(List<AccessorInfo> accessors) {
+    static String toShortString(List<LeaseInfo> leaseInfos) {
         final StringBuilder sb = new StringBuilder();
         sb.append("[");
-        for (int i = 0, size = accessors.size(); i < size; ++i) {
-            sb.append(accessors.get(i).toShortString());
+        for (int i = 0, size = leaseInfos.size(); i < size; ++i) {
+            sb.append(leaseInfos.get(i).toShortString());
             sb.append(",");
         }
         sb.append("]");
@@ -103,17 +114,17 @@
     }
 
     @NonNull
-    public static final Creator<AccessorInfo> CREATOR = new Creator<AccessorInfo>() {
+    public static final Creator<LeaseInfo> CREATOR = new Creator<LeaseInfo>() {
         @Override
         @NonNull
-        public AccessorInfo createFromParcel(Parcel source) {
-            return new AccessorInfo(source);
+        public LeaseInfo createFromParcel(Parcel source) {
+            return new LeaseInfo(source);
         }
 
         @Override
         @NonNull
-        public AccessorInfo[] newArray(int size) {
-            return new AccessorInfo[size];
+        public LeaseInfo[] newArray(int size) {
+            return new LeaseInfo[size];
         }
     };
 }
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 970766d..8b640ca 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -38,6 +38,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.blob.BlobHandle;
+import android.app.blob.LeaseInfo;
 import android.content.Context;
 import android.content.res.ResourceId;
 import android.content.res.Resources;
@@ -281,6 +282,25 @@
         return false;
     }
 
+    @Nullable
+    LeaseInfo getLeaseInfo(@NonNull String packageName, int uid) {
+        synchronized (mMetadataLock) {
+            for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+                final Leasee leasee = mLeasees.valueAt(i);
+                if (leasee.uid == uid && leasee.packageName.equals(packageName)) {
+                    final int descriptionResId = leasee.descriptionResEntryName == null
+                            ? Resources.ID_NULL
+                            : BlobStoreUtils.getDescriptionResourceId(
+                                    mContext, leasee.descriptionResEntryName, leasee.packageName,
+                                    UserHandle.getUserId(leasee.uid));
+                    return new LeaseInfo(packageName, leasee.expiryTimeMillis,
+                            descriptionResId, leasee.description);
+                }
+            }
+        }
+        return null;
+    }
+
     void forEachLeasee(Consumer<Leasee> consumer) {
         mLeasees.forEach(consumer);
     }
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 53a97ce..f4b8f0f 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -45,11 +45,11 @@
 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.app.blob.LeaseInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -454,17 +454,17 @@
                 return packageResources;
             };
             getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
-                final ArrayList<AccessorInfo> accessorInfos = new ArrayList<>();
+                final ArrayList<LeaseInfo> leaseInfos = 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,
+                    leaseInfos.add(new LeaseInfo(leasee.packageName, leasee.expiryTimeMillis,
                             descriptionResId, leasee.description));
                 });
                 blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
-                        blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), accessorInfos));
+                        blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), leaseInfos));
             });
         }
         return blobInfos;
@@ -482,6 +482,31 @@
         }
     }
 
+    private List<BlobHandle> getLeasedBlobsInternal(int callingUid,
+            @NonNull String callingPackage) {
+        final ArrayList<BlobHandle> leasedBlobs = new ArrayList<>();
+        forEachBlobInUser(blobMetadata -> {
+            if (blobMetadata.isALeasee(callingPackage, callingUid)) {
+                leasedBlobs.add(blobMetadata.getBlobHandle());
+            }
+        }, UserHandle.getUserId(callingUid));
+        return leasedBlobs;
+    }
+
+    private LeaseInfo getLeaseInfoInternal(BlobHandle blobHandle,
+            int callingUid, @NonNull String callingPackage) {
+        synchronized (mBlobsLock) {
+            final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
+                    .get(blobHandle);
+            if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
+                    callingPackage, callingUid)) {
+                throw new SecurityException("Caller not allowed to access " + blobHandle
+                        + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
+            }
+            return blobMetadata.getLeaseInfo(callingPackage, callingUid);
+        }
+    }
+
     private void verifyCallingPackage(int callingUid, String callingPackage) {
         if (mPackageManagerInternal.getPackageUid(
                 callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) {
@@ -1267,6 +1292,12 @@
             final int callingUid = Binder.getCallingUid();
             verifyCallingPackage(callingUid, packageName);
 
+            if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
+                    packageName, UserHandle.getUserId(callingUid))) {
+                throw new SecurityException("Caller not allowed to open blob; "
+                        + "callingUid=" + callingUid + ", callingPackage=" + packageName);
+            }
+
             try {
                 acquireLeaseInternal(blobHandle, descriptionResId, description,
                         leaseExpiryTimeMillis, callingUid, packageName);
@@ -1284,6 +1315,12 @@
             final int callingUid = Binder.getCallingUid();
             verifyCallingPackage(callingUid, packageName);
 
+            if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
+                    packageName, UserHandle.getUserId(callingUid))) {
+                throw new SecurityException("Caller not allowed to open blob; "
+                        + "callingUid=" + callingUid + ", callingPackage=" + packageName);
+            }
+
             releaseLeaseInternal(blobHandle, callingUid, packageName);
         }
 
@@ -1320,6 +1357,36 @@
         }
 
         @Override
+        @NonNull
+        public List<BlobHandle> getLeasedBlobs(@NonNull String packageName) {
+            Objects.requireNonNull(packageName, "packageName must not be null");
+
+            final int callingUid = Binder.getCallingUid();
+            verifyCallingPackage(callingUid, packageName);
+
+            return getLeasedBlobsInternal(callingUid, packageName);
+        }
+
+        @Override
+        @Nullable
+        public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
+            Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+            blobHandle.assertIsValid();
+            Objects.requireNonNull(packageName, "packageName must not be null");
+
+            final int callingUid = Binder.getCallingUid();
+            verifyCallingPackage(callingUid, packageName);
+
+            if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp(
+                    packageName, UserHandle.getUserId(callingUid))) {
+                throw new SecurityException("Caller not allowed to open blob; "
+                        + "callingUid=" + callingUid + ", callingPackage=" + packageName);
+            }
+
+            return getLeaseInfoInternal(blobHandle, callingUid, packageName);
+        }
+
+        @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
index 6af540a..fabce76 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java
@@ -47,4 +47,13 @@
             @NonNull String resourceEntryName, @NonNull String packageName) {
         return resources.getIdentifier(resourceEntryName, DESC_RES_TYPE_STRING, packageName);
     }
+
+    @IdRes
+    static int getDescriptionResourceId(@NonNull Context context,
+            @NonNull String resourceEntryName, @NonNull String packageName, int userId) {
+        final Resources resources = getPackageResources(context, packageName, userId);
+        return resources == null
+                ? Resources.ID_NULL
+                : getDescriptionResourceId(resources, resourceEntryName, packageName);
+    }
 }
diff --git a/api/current.txt b/api/current.txt
index a85d632..da9fd09 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -290,6 +290,7 @@
     field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
+    field public static final int allowDontAutoRevokePermissions = 16844309; // 0x1010615
     field public static final int allowEmbedded = 16843765; // 0x10103f5
     field public static final int allowNativeHeapPointerTagging = 16844307; // 0x1010613
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
@@ -572,6 +573,7 @@
     field public static final int elevation = 16843840; // 0x1010440
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
+    field public static final int enableGwpAsan = 16844312; // 0x1010618
     field public static final int enableVrMode = 16844069; // 0x1010525
     field public static final int enabled = 16842766; // 0x101000e
     field public static final int end = 16843996; // 0x10104dc
@@ -620,7 +622,6 @@
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
-    field public static final int featureId = 16844301; // 0x101060d
     field public static final int fillAfter = 16843197; // 0x10101bd
     field public static final int fillAlpha = 16843980; // 0x10104cc
     field public static final int fillBefore = 16843196; // 0x10101bc
@@ -953,7 +954,7 @@
     field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
-    field public static final int mimeGroup = 16844309; // 0x1010615
+    field public static final int mimeGroup = 16844311; // 0x1010617
     field public static final int mimeType = 16842790; // 0x1010026
     field public static final int min = 16844089; // 0x1010539
     field public static final int minAspectRatio = 16844187; // 0x101059b
@@ -1082,7 +1083,7 @@
     field public static final int preferenceScreenStyle = 16842891; // 0x101008b
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
-    field public static final int preserveLegacyExternalStorage = 16844308; // 0x1010614
+    field public static final int preserveLegacyExternalStorage = 16844310; // 0x1010616
     field public static final int previewImage = 16843482; // 0x10102da
     field public static final int primaryContentAlpha = 16844114; // 0x1010552
     field public static final int priority = 16842780; // 0x101001c
@@ -1139,6 +1140,7 @@
     field public static final int reqKeyboardType = 16843304; // 0x1010228
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
+    field public static final int requestDontAutoRevokePermissions = 16844308; // 0x1010614
     field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
@@ -4586,7 +4588,7 @@
 
   public final class AsyncNotedAppOp implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public String getFeatureId();
+    method @Nullable public String getAttributionTag();
     method @NonNull public String getMessage();
     method @IntRange(from=0) public int getNotingUid();
     method @NonNull public String getOp();
@@ -6430,7 +6432,7 @@
   public final class SyncNotedAppOp implements android.os.Parcelable {
     ctor public SyncNotedAppOp(@IntRange(from=0L) int, @Nullable String);
     method public int describeContents();
-    method @Nullable public String getFeatureId();
+    method @Nullable public String getAttributionTag();
     method @NonNull public String getOp();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.SyncNotedAppOp> CREATOR;
@@ -6856,9 +6858,9 @@
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
     method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
-    method public boolean getAutoTime(@NonNull android.content.ComponentName);
+    method public boolean getAutoTimeEnabled(@NonNull android.content.ComponentName);
     method @Deprecated public boolean getAutoTimeRequired();
-    method public boolean getAutoTimeZone(@NonNull android.content.ComponentName);
+    method public boolean getAutoTimeZoneEnabled(@NonNull android.content.ComponentName);
     method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
     method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
     method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
@@ -6910,7 +6912,6 @@
     method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
     method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
     method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
-    method @NonNull public java.util.List<java.lang.String> getProtectedPackages(@NonNull android.content.ComponentName);
     method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
     method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
@@ -6921,6 +6922,7 @@
     method @Nullable public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
     method @Nullable public android.os.PersistableBundle getTransferOwnershipBundle();
     method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
+    method @NonNull public java.util.List<java.lang.String> getUserControlDisabledPackages(@NonNull android.content.ComponentName);
     method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
     method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
     method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
@@ -6982,9 +6984,9 @@
     method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void setAutoTime(@NonNull android.content.ComponentName, boolean);
+    method public void setAutoTimeEnabled(@NonNull android.content.ComponentName, boolean);
     method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
-    method public void setAutoTimeZone(@NonNull android.content.ComponentName, boolean);
+    method public void setAutoTimeZoneEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
@@ -7040,7 +7042,6 @@
     method public void setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean);
     method public void setProfileEnabled(@NonNull android.content.ComponentName);
     method public void setProfileName(@NonNull android.content.ComponentName, String);
-    method public void setProtectedPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
     method public void setRecommendedGlobalProxy(@NonNull android.content.ComponentName, @Nullable android.net.ProxyInfo);
     method public void setRequiredStrongAuthTimeout(@NonNull android.content.ComponentName, long);
     method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
@@ -7059,6 +7060,7 @@
     method public boolean setTimeZone(@NonNull android.content.ComponentName, String);
     method public void setTrustAgentConfiguration(@NonNull android.content.ComponentName, @NonNull android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(@Nullable android.content.ComponentName, String, boolean);
+    method public void setUserControlDisabledPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
     method public void setUserIcon(@NonNull android.content.ComponentName, android.graphics.Bitmap);
     method public int startUserInBackground(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
     method public int stopUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
@@ -9696,7 +9698,7 @@
     method public abstract int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]);
     method public int delete(@NonNull android.net.Uri, @Nullable android.os.Bundle);
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
-    method @Nullable public final String getCallingFeatureId();
+    method @Nullable public final String getCallingAttributionTag();
     method @Nullable public final String getCallingPackage();
     method @Nullable public final String getCallingPackageUnchecked();
     method @Nullable public final android.content.Context getContext();
@@ -10030,11 +10032,11 @@
     method @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)") public abstract int checkUriPermission(android.net.Uri, int, int, int);
     method @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)") public abstract int checkUriPermission(@Nullable android.net.Uri, @Nullable String, @Nullable String, int, int, int);
     method @Deprecated public abstract void clearWallpaper() throws java.io.IOException;
+    method @NonNull public android.content.Context createAttributionContext(@Nullable String);
     method public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration);
     method public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.Context createDeviceProtectedStorageContext();
     method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
-    method @NonNull public android.content.Context createFeatureContext(@Nullable String);
     method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public android.content.Context createWindowContext(int, @Nullable android.os.Bundle);
     method public abstract String[] databaseList();
@@ -10052,6 +10054,7 @@
     method public abstract android.content.Context getApplicationContext();
     method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
     method public abstract android.content.res.AssetManager getAssets();
+    method @Nullable public String getAttributionTag();
     method public abstract java.io.File getCacheDir();
     method public abstract ClassLoader getClassLoader();
     method public abstract java.io.File getCodeCacheDir();
@@ -10068,7 +10071,6 @@
     method @Nullable public abstract java.io.File getExternalFilesDir(@Nullable String);
     method public abstract java.io.File[] getExternalFilesDirs(String);
     method @Deprecated public abstract java.io.File[] getExternalMediaDirs();
-    method @Nullable public String getFeatureId();
     method public abstract java.io.File getFileStreamPath(String);
     method public abstract java.io.File getFilesDir();
     method public java.util.concurrent.Executor getMainExecutor();
@@ -11439,6 +11441,7 @@
     method public int describeContents();
     method public void dump(android.util.Printer, String);
     method public static CharSequence getCategoryTitle(android.content.Context, int);
+    method @Nullable public Boolean isGwpAsanEnabled();
     method public boolean isProfileableByShell();
     method public boolean isResourceOverlay();
     method public boolean isVirtualPreload();
@@ -11893,6 +11896,7 @@
     method public void setAppIcon(@Nullable android.graphics.Bitmap);
     method public void setAppLabel(@Nullable CharSequence);
     method public void setAppPackageName(@Nullable String);
+    method public void setAutoRevokePermissionsMode(boolean);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setMultiPackage();
@@ -12022,6 +12026,8 @@
     method public boolean hasSigningCertificate(int, @NonNull byte[], int);
     method public abstract boolean hasSystemFeature(@NonNull String);
     method public abstract boolean hasSystemFeature(@NonNull String, int);
+    method @RequiresPermission(value="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS", conditional=true) public boolean isAutoRevokeWhitelisted(@NonNull String);
+    method public boolean isAutoRevokeWhitelisted();
     method public boolean isDefaultApplicationIcon(@NonNull android.graphics.drawable.Drawable);
     method public boolean isDeviceUpgrading();
     method public abstract boolean isInstantApp();
@@ -12046,6 +12052,7 @@
     method @Nullable public abstract android.content.pm.ResolveInfo resolveService(@NonNull android.content.Intent, int);
     method public abstract void setApplicationCategoryHint(@NonNull String, int);
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int);
+    method @RequiresPermission(value="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS", conditional=true) public boolean setAutoRevokeWhitelisted(@NonNull String, boolean);
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
     method public abstract void setInstallerPackageName(@NonNull String, @Nullable String);
     method public void setMimeGroup(@NonNull String, @NonNull java.util.Set<java.lang.String>);
@@ -17352,7 +17359,7 @@
   public final class CameraManager {
     method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
     method @NonNull public String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
-    method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getConcurrentStreamingCameraIds() throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getConcurrentCameraIds() throws android.hardware.camera2.CameraAccessException;
     method @RequiresPermission(android.Manifest.permission.CAMERA) public boolean isConcurrentSessionConfigurationSupported(@NonNull java.util.Map<java.lang.String,android.hardware.camera2.params.SessionConfiguration>) throws android.hardware.camera2.CameraAccessException;
     method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull android.hardware.camera2.CameraDevice.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
@@ -20094,8 +20101,7 @@
     method public T numberFormatterSecond(android.icu.number.UnlocalizedNumberFormatter);
   }
 
-  public abstract class Precision implements java.lang.Cloneable {
-    method public Object clone();
+  public abstract class Precision {
     method public static android.icu.number.CurrencyPrecision currency(android.icu.util.Currency.CurrencyUsage);
     method public static android.icu.number.FractionPrecision fixedFraction(int);
     method public static android.icu.number.Precision fixedSignificantDigits(int);
@@ -20118,8 +20124,7 @@
     method public static android.icu.number.Scale powerOfTen(int);
   }
 
-  public class ScientificNotation extends android.icu.number.Notation implements java.lang.Cloneable {
-    method public Object clone();
+  public class ScientificNotation extends android.icu.number.Notation {
     method public android.icu.number.ScientificNotation withExponentSignDisplay(android.icu.number.NumberFormatter.SignDisplay);
     method public android.icu.number.ScientificNotation withMinExponentDigits(int);
   }
@@ -27046,7 +27051,7 @@
     method public abstract void onVolumeUpdateRequest(android.media.MediaRouter.RouteInfo, int);
   }
 
-  public class MediaRouter2 {
+  public final class MediaRouter2 {
     method @NonNull public java.util.List<android.media.MediaRouter2.RoutingController> getControllers();
     method @NonNull public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context);
     method @NonNull public java.util.List<android.media.MediaRoute2Info> getRoutes();
@@ -37155,12 +37160,10 @@
     method @Nullable public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
     method @NonNull public android.os.VibrationEffect compose();
     field public static final int PRIMITIVE_CLICK = 1; // 0x1
-    field public static final int PRIMITIVE_LIGHT_TICK = 7; // 0x7
     field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6
     field public static final int PRIMITIVE_QUICK_RISE = 4; // 0x4
     field public static final int PRIMITIVE_SLOW_RISE = 5; // 0x5
-    field public static final int PRIMITIVE_SPIN = 3; // 0x3
-    field public static final int PRIMITIVE_THUD = 2; // 0x2
+    field public static final int PRIMITIVE_TICK = 7; // 0x7
   }
 
   public abstract class Vibrator {
@@ -40716,6 +40719,7 @@
     field public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
     field public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
     field public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+    field public static final String SECURE_FRP_MODE = "secure_frp_mode";
     field public static final String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
     field public static final String SETTINGS_CLASSNAME = "settings_classname";
     field public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
@@ -43014,12 +43018,12 @@
   }
 
   public static final class Dataset.Builder {
-    ctor public Dataset.Builder(@NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation);
     ctor public Dataset.Builder(@NonNull android.widget.RemoteViews);
     ctor public Dataset.Builder();
     method @NonNull public android.service.autofill.Dataset build();
     method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
     method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
+    method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern);
@@ -48994,8 +48998,8 @@
     ctor public RegistrationManager.RegistrationCallback();
     method public void onRegistered(int);
     method public void onRegistering(int);
-    method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
-    method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
+    method public void onTechnologyChangeFailed(int, @NonNull android.telephony.ims.ImsReasonInfo);
+    method public void onUnregistered(@NonNull android.telephony.ims.ImsReasonInfo);
   }
 
 }
@@ -53603,10 +53607,11 @@
 
   public class SurfaceControlViewHost {
     ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
-    method public void addView(@NonNull android.view.View, int, int);
     method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
+    method @Nullable public android.view.View getView();
     method public void relayout(int, int);
     method public void release();
+    method public void setView(@NonNull android.view.View, int, int);
   }
 
   public static final class SurfaceControlViewHost.SurfacePackage implements android.os.Parcelable {
@@ -55581,7 +55586,7 @@
 
   public interface WindowInsetsController {
     method public void addOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener);
-    method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
+    method public void controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @Nullable android.os.CancellationSignal, @NonNull android.view.WindowInsetsAnimationControlListener);
     method public int getSystemBarsAppearance();
     method public int getSystemBarsBehavior();
     method public void hide(int);
@@ -56739,6 +56744,7 @@
     method public final void notifySessionResumed();
     method public final void notifyViewAppeared(@NonNull android.view.ViewStructure);
     method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId);
+    method public final void notifyViewInsetsChanged(@NonNull android.graphics.Insets);
     method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence);
     method public final void notifyViewsDisappeared(@NonNull android.view.autofill.AutofillId, @NonNull long[]);
     method public final void setContentCaptureContext(@Nullable android.view.contentcapture.ContentCaptureContext);
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 69b52693..ee997f1 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -29,7 +29,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
   }
 
-  public class TetheringConstants {
+  public final class TetheringConstants {
     field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
     field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
     field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
diff --git a/api/removed.txt b/api/removed.txt
index 8537b21..077c915 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,4 +1,12 @@
 // Signature format: 2.0
+package android {
+
+  public static final class R.attr {
+    field public static final int featureId = 16844301; // 0x101060d
+  }
+
+}
+
 package android.app {
 
   public class ActivityManager {
@@ -69,11 +77,17 @@
 
 package android.content {
 
+  public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
+    method @Deprecated @Nullable public final String getCallingFeatureId();
+  }
+
   public abstract class ContentResolver {
     method @Deprecated public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
   }
 
   public abstract class Context {
+    method @Deprecated @NonNull public android.content.Context createFeatureContext(@Nullable String);
+    method @Deprecated @Nullable public String getFeatureId();
     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 b7aa9da..d0622d2 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -235,6 +235,7 @@
     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_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
     field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
     field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
@@ -407,7 +408,6 @@
     field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
     field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
     field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
-    field public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
     field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
     field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
     field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
@@ -448,14 +448,37 @@
     field public static final int UID_STATE_TOP = 200; // 0xc8
   }
 
-  public static final class AppOpsManager.HistoricalFeatureOps implements android.os.Parcelable {
+  public static final class AppOpsManager.AttributedHistoricalOps implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public String getFeatureId();
     method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
     method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
     method @IntRange(from=0) public int getOpCount();
+    method @Nullable public String getTag();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalFeatureOps> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedHistoricalOps> CREATOR;
+  }
+
+  public static final class AppOpsManager.AttributedOpEntry implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getLastAccessBackgroundTime(int);
+    method public long getLastAccessForegroundTime(int);
+    method public long getLastAccessTime(int);
+    method public long getLastAccessTime(int, int, int);
+    method public long getLastBackgroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+    method public long getLastDuration(int);
+    method public long getLastDuration(int, int, int);
+    method public long getLastForegroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
+    method public long getLastRejectBackgroundTime(int);
+    method public long getLastRejectForegroundTime(int);
+    method public long getLastRejectTime(int);
+    method public long getLastRejectTime(int, int, int);
+    method public boolean isRunning();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedOpEntry> CREATOR;
   }
 
   public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
@@ -491,7 +514,7 @@
   public static final class AppOpsManager.HistoricalOpsRequest.Builder {
     ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
-    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFeatureId(@Nullable String);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
@@ -500,9 +523,9 @@
 
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method @IntRange(from=0) public int getFeatureCount();
-    method @Nullable public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOps(@NonNull String);
-    method @NonNull public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOpsAt(@IntRange(from=0) int);
+    method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@NonNull String);
+    method @NonNull public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOpsAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getAttributedOpsCount();
     method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
     method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
     method @IntRange(from=0) public int getOpCount();
@@ -523,8 +546,8 @@
 
   public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();
     method @Deprecated public long getDuration();
-    method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.OpFeatureEntry> getFeatures();
     method public long getLastAccessBackgroundTime(int);
     method public long getLastAccessForegroundTime(int);
     method public long getLastAccessTime(int);
@@ -554,36 +577,13 @@
 
   public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public String getFeatureId();
+    method @Nullable public String getAttributionTag();
     method @Nullable public String getPackageName();
     method @IntRange(from=0) public int getUid();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
   }
 
-  public static final class AppOpsManager.OpFeatureEntry implements android.os.Parcelable {
-    method public int describeContents();
-    method public long getLastAccessBackgroundTime(int);
-    method public long getLastAccessForegroundTime(int);
-    method public long getLastAccessTime(int);
-    method public long getLastAccessTime(int, int, int);
-    method public long getLastBackgroundDuration(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
-    method public long getLastDuration(int);
-    method public long getLastDuration(int, int, int);
-    method public long getLastForegroundDuration(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
-    method public long getLastRejectBackgroundTime(int);
-    method public long getLastRejectForegroundTime(int);
-    method public long getLastRejectTime(int);
-    method public long getLastRejectTime(int, int, int);
-    method public boolean isRunning();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpFeatureEntry> CREATOR;
-  }
-
   public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
@@ -688,7 +688,7 @@
   public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {
     ctor public RuntimeAppOpAccessMessage(@IntRange(from=0L) int, @IntRange(from=0L) int, @NonNull String, @Nullable String, @NonNull String, int);
     method public int describeContents();
-    method @Nullable public String getFeatureId();
+    method @Nullable public String getAttributionTag();
     method @NonNull public String getMessage();
     method @NonNull public String getOp();
     method @NonNull public String getPackageName();
@@ -757,7 +757,6 @@
   public class StatusBarManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
     method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
-    method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
   }
 
   public static final class StatusBarManager.DisableInfo {
@@ -1371,7 +1370,6 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @Nullable public String getDefaultSmsPackage(int);
     method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
@@ -2133,6 +2131,7 @@
   public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
     method public boolean getAllocateAggressive();
     method @Deprecated public boolean getAllowDowngrade();
+    method public int getAutoRevokePermissionsMode();
     method public boolean getDontKillApp();
     method public boolean getEnableRollback();
     method @Nullable public String[] getGrantedRuntimePermissions();
@@ -2216,7 +2215,7 @@
     field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
     field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
     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 FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = -268435456; // 0xf0000000
     field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
     field public static final int FLAG_PERMISSION_AUTO_REVOKED = 131072; // 0x20000
     field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
@@ -2281,7 +2280,6 @@
     field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ANY_USER = 4194304; // 0x400000
     field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
-    field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
     field public static final int MATCH_INSTANT = 8388608; // 0x800000
     field public static final int MODULE_APEX_NAME = 1; // 0x1
     field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
@@ -5488,7 +5486,7 @@
   public class DvbcFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder builder(@NonNull android.content.Context);
     method public int getAnnex();
-    method public long getFec();
+    method public long getInnerFec();
     method public int getModulation();
     method public int getOuterFec();
     method public int getSpectralInversion();
@@ -5516,7 +5514,7 @@
   public static class DvbcFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder> {
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setAnnex(int);
-    method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFec(long);
+    method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setInnerFec(long);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setModulation(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
@@ -5782,9 +5780,9 @@
     method public int getAgc();
     method @NonNull public android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpInfo[] getAtsc3PlpInfo();
     method public int getBer();
-    method public long getFec();
     method public int getFreqOffset();
     method public int getHierarchy();
+    method public long getInnerFec();
     method @NonNull public boolean[] getLayerErrors();
     method public int getLnbVoltage();
     method public int getMer();
@@ -6090,7 +6088,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
-    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     method @Deprecated public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int, int, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
@@ -6099,7 +6097,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
-    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
     field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -6287,7 +6285,6 @@
     method @Nullable public android.net.Network getNetwork();
     method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
     method public void onAutomaticReconnectDisabled();
-    method public void onBandwidthUpdateRequested();
     method public void onNetworkUnwanted();
     method public void onRemoveKeepalivePacketFilter(int);
     method public void onSaveAcceptUnvalidated(boolean);
@@ -6301,23 +6298,17 @@
     method public void sendNetworkScore(int);
     method public void sendSocketKeepaliveEvent(int, int);
     method public void setConnected();
-    method @Deprecated public void setLegacyExtraInfo(@Nullable String);
-    method @Deprecated public void setLegacySubtype(int, @NonNull String);
     method public void unregister();
     field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
     field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
-    field public final int providerId;
   }
 
   public final class NetworkAgentConfig implements android.os.Parcelable {
     method public int describeContents();
     method public int getLegacyType();
     method @NonNull public String getLegacyTypeName();
-    method @Nullable public String getSubscriberId();
     method public boolean isExplicitlySelected();
-    method public boolean isNat64DetectionEnabled();
     method public boolean isPartialConnectivityAcceptable();
-    method public boolean isProvisioningNotificationEnabled();
     method public boolean isUnvalidatedConnectivityAcceptable();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
@@ -6326,18 +6317,14 @@
   public static class NetworkAgentConfig.Builder {
     ctor public NetworkAgentConfig.Builder();
     method @NonNull public android.net.NetworkAgentConfig build();
-    method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
-    method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
     method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
     method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
-    method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
-    method public boolean deduceRestrictedCapability();
     method @NonNull public java.util.List<java.lang.Integer> getAdministratorUids();
     method @Nullable public String getSSID();
     method @NonNull public int[] getTransportTypes();
@@ -6362,27 +6349,9 @@
     field public final android.net.WifiKey wifiKey;
   }
 
-  public class NetworkPolicyManager {
-    method @NonNull public android.telephony.SubscriptionPlan[] getSubscriptionPlans(int, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerSubscriptionCallback(@NonNull android.net.NetworkPolicyManager.SubscriptionCallback);
-    method public void setSubscriptionOverride(int, int, int, long, @NonNull String);
-    method public void setSubscriptionPlans(int, @NonNull android.telephony.SubscriptionPlan[], @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterSubscriptionCallback(@NonNull android.net.NetworkPolicyManager.SubscriptionCallback);
-    field public static final int SUBSCRIPTION_OVERRIDE_CONGESTED = 2; // 0x2
-    field public static final int SUBSCRIPTION_OVERRIDE_UNMETERED = 1; // 0x1
-  }
-
-  public static class NetworkPolicyManager.SubscriptionCallback {
-    ctor public NetworkPolicyManager.SubscriptionCallback();
-    method public void onSubscriptionOverride(int, int, int);
-    method public void onSubscriptionPlansChanged(int, @NonNull android.telephony.SubscriptionPlan[]);
-  }
-
   public class NetworkProvider {
     ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
-    method @Nullable public android.os.Messenger getMessenger();
-    method @NonNull public String getName();
     method public int getProviderId();
     method public void onNetworkRequested(@NonNull android.net.NetworkRequest, int, int);
     method public void onRequestWithdrawn(@NonNull android.net.NetworkRequest);
@@ -8225,13 +8194,15 @@
     field public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
     field public static final String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
     field public static final String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
-    field public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB = "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
+    field @RequiresPermission("android.permission.UPDATE_CONFIG") public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB = "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
     field public static final String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
     field public static final String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
     field public static final String ACTION_UPDATE_NETWORK_WATCHLIST = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
     field public static final String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
     field public static final String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
     field public static final String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
+    field public static final String EXTRA_REQUIRED_HASH = "android.os.extra.REQUIRED_HASH";
+    field public static final String EXTRA_VERSION = "android.os.extra.VERSION";
   }
 
   public class Environment {
@@ -8941,11 +8912,13 @@
     method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
     method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
-    method @BinderThread public void onUpdateUserSensitivePermissionFlags();
+    method @BinderThread public void onUpdateUserSensitivePermissionFlags(int, @NonNull Runnable);
     field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
   }
 
   public final class PermissionManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
     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>);
@@ -9366,7 +9339,6 @@
     field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
     field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
     field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
-    field public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
     field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
     field public static final String DOZE_ALWAYS_ON = "doze_always_on";
     field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
@@ -9379,7 +9351,6 @@
     field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
     field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
     field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
-    field public static final String SECURE_FRP_MODE = "secure_frp_mode";
     field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
     field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
     field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
@@ -9426,9 +9397,7 @@
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final String APN_SET_ID = "apn_set_id";
     field public static final int CARRIER_EDITED = 4; // 0x4
-    field @NonNull public static final android.net.Uri DPC_URI;
     field public static final String EDITED_STATUS = "edited";
-    field public static final int INVALID_APN_ID = -1; // 0xffffffff
     field public static final String MAX_CONNECTIONS = "max_conns";
     field public static final String MODEM_PERSIST = "modem_cognitive";
     field public static final String MTU = "mtu";
@@ -9797,7 +9766,7 @@
 
   public static final class Dataset.Builder {
     ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation);
-    method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
   }
 
   public abstract class InlineSuggestionRenderService extends android.app.Service {
@@ -11539,9 +11508,7 @@
   }
 
   public class TelephonyManager {
-    method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int changeIccLockPassword(@NonNull String, @NonNull String);
     method public int checkCarrierPrivilegesForPackage(String);
     method public int checkCarrierPrivilegesForPackageAnyPhone(String);
     method public void dial(String);
@@ -11565,19 +11532,16 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int);
     method public String getCdmaPrlVersion();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode();
     method public int getCurrentPhoneType();
     method public int getCurrentPhoneType(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState();
     method @Deprecated public boolean getDataEnabled();
     method @Deprecated public boolean getDataEnabled(int);
     method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
-    method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
-    method public int getEmergencyNumberDbVersion();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
     method public int getMaxNumberOfSimultaneouslyActiveSims();
@@ -11604,12 +11568,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataAllowedInVoiceCall();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionEnabled();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
     method public boolean isDataConnectivityPossible();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled();
@@ -11622,7 +11584,6 @@
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
-    method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyUserActivity();
@@ -11644,13 +11605,9 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCdmaRoamingMode(int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCdmaSubscriptionMode(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setDataAllowedDuringVoiceCall(boolean);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setIccLockEnabled(boolean, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
@@ -11700,10 +11657,6 @@
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
-    field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1
-    field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0
-    field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff
-    field public static final int CHANGE_ICC_LOCK_SUCCESS = 2147483647; // 0x7fffffff
     field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
     field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
     field @Deprecated public static final String EXTRA_APN_PROTOCOL = "apnProto";
@@ -12325,10 +12278,6 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR;
   }
 
-  public class ImsManager {
-    field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
-  }
-
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
@@ -12594,82 +12543,12 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
-    field public static final int KEY_1X_EPDG_TIMER_SEC = 64; // 0x40
-    field public static final int KEY_1X_THRESHOLD = 59; // 0x3b
-    field public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; // 0x32
-    field public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; // 0x0
-    field public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; // 0x35
-    field public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; // 0x31
-    field public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; // 0x30
-    field public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; // 0x1
-    field public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; // 0x2f
-    field public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; // 0x34
-    field public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; // 0x33
-    field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19
-    field public static final int KEY_ENABLE_SILENT_REDIAL = 6; // 0x6
-    field public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; // 0x1f
-    field public static final int KEY_LTE_EPDG_TIMER_SEC = 62; // 0x3e
-    field public static final int KEY_LTE_THRESHOLD_1 = 56; // 0x38
-    field public static final int KEY_LTE_THRESHOLD_2 = 57; // 0x39
-    field public static final int KEY_LTE_THRESHOLD_3 = 58; // 0x3a
-    field public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; // 0x3
-    field public static final int KEY_MOBILE_DATA_ENABLED = 29; // 0x1d
-    field public static final int KEY_MULTIENDPOINT_ENABLED = 65; // 0x41
-    field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13
-    field public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; // 0x12
-    field public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; // 0x14
-    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_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
-    field public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; // 0x22
-    field public static final int KEY_RTP_SPEECH_END_PORT = 36; // 0x24
-    field public static final int KEY_RTP_SPEECH_START_PORT = 35; // 0x23
-    field public static final int KEY_RTT_ENABLED = 66; // 0x42
-    field public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; // 0x2b
-    field public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; // 0x2c
-    field public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; // 0x26
-    field public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; // 0x4
-    field public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; // 0x25
-    field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; // 0x2a
-    field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; // 0x27
-    field public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; // 0x20
-    field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; // 0x2d
-    field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; // 0x28
-    field public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; // 0x2e
-    field public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; // 0x29
-    field public static final int KEY_SIP_SESSION_TIMER_SEC = 2; // 0x2
-    field public static final int KEY_SMS_FORMAT = 13; // 0xd
-    field public static final int KEY_SMS_OVER_IP_ENABLED = 14; // 0xe
-    field public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; // 0x36
-    field public static final int KEY_T1_TIMER_VALUE_MS = 7; // 0x7
-    field public static final int KEY_T2_TIMER_VALUE_MS = 8; // 0x8
-    field public static final int KEY_TF_TIMER_VALUE_MS = 9; // 0x9
-    field public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; // 0x5
-    field public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; // 0x18
-    field public static final int KEY_VIDEO_QUALITY = 55; // 0x37
-    field public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // 0x1c
     field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
     field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
-    field public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; // 0xa
-    field public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; // 0x1e
-    field public static final int KEY_VT_PROVISIONING_STATUS = 11; // 0xb
-    field public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; // 0x3f
-    field public static final int KEY_WIFI_THRESHOLD_A = 60; // 0x3c
-    field public static final int KEY_WIFI_THRESHOLD_B = 61; // 0x3d
-    field public static final int PROVISIONING_RESULT_UNKNOWN = -1; // 0xffffffff
     field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
     field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
-    field public static final int SMS_FORMAT_3GPP = 1; // 0x1
-    field public static final int SMS_FORMAT_3GPP2 = 0; // 0x0
     field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
     field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
-    field public static final int VIDEO_QUALITY_HIGH = 1; // 0x1
-    field public static final int VIDEO_QUALITY_LOW = 0; // 0x0
   }
 
   public static class ProvisioningManager.Callback {
@@ -12678,56 +12557,6 @@
     method public void onProvisioningStringChanged(int, @NonNull String);
   }
 
-  public final class RcsContactUceCapability implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
-    method @NonNull public android.net.Uri getContactUri();
-    method @Nullable public android.net.Uri getServiceUri(long);
-    method public boolean isCapable(long);
-    method public boolean isCapable(@NonNull String);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
-    field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000
-    field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000
-    field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2
-    field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4
-    field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1
-    field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000
-    field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8
-    field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40
-    field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80
-    field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20
-    field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10
-    field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000
-    field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000
-    field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000
-    field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000
-    field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
-    field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
-    field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
-    field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
-    field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
-    field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
-    field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
-    field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000
-    field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000
-    field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
-    field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
-    field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
-    field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
-    field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
-    field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
-  }
-
-  public static class RcsContactUceCapability.Builder {
-    ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability build();
-  }
-
   public class RcsUceAdapter {
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
   }
@@ -12974,24 +12803,12 @@
     method public int transact(android.os.Bundle);
     method public int updateCallBarring(int, int, String[]);
     method public int updateCallBarringForServiceClass(int, int, String[], int);
-    method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
     method public int updateCallForward(int, int, String, int, int);
     method public int updateCallWaiting(boolean, int);
     method public int updateClip(boolean);
     method public int updateClir(int);
     method public int updateColp(boolean);
     method public int updateColr(int);
-    field public static final int CALL_BARRING_ALL = 7; // 0x7
-    field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1
-    field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2
-    field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6
-    field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9
-    field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8
-    field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3
-    field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4
-    field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa
-    field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5
-    field public static final int INVALID_RESULT = -1; // 0xffffffff
   }
 
 }
@@ -13196,6 +13013,7 @@
     method public long getEventTime();
     method @Nullable public android.view.autofill.AutofillId getId();
     method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
+    method @Nullable public android.graphics.Insets getInsets();
     method @Nullable public CharSequence getText();
     method public int getType();
     method @Nullable public android.view.contentcapture.ViewNode getViewNode();
@@ -13206,6 +13024,7 @@
     field public static final int TYPE_SESSION_RESUMED = 7; // 0x7
     field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
     field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
+    field public static final int TYPE_VIEW_INSETS_CHANGED = 9; // 0x9
     field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
     field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5
     field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4
diff --git a/api/test-current.txt b/api/test-current.txt
index 4f4c82b..08888d7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -83,6 +83,7 @@
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
     method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
     field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
     field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1
     field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6
@@ -263,14 +264,37 @@
     field public static final int UID_STATE_TOP = 200; // 0xc8
   }
 
-  public static final class AppOpsManager.HistoricalFeatureOps implements android.os.Parcelable {
+  public static final class AppOpsManager.AttributedHistoricalOps implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public String getFeatureId();
     method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
     method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
     method @IntRange(from=0) public int getOpCount();
+    method @Nullable public String getTag();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalFeatureOps> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedHistoricalOps> CREATOR;
+  }
+
+  public static final class AppOpsManager.AttributedOpEntry implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getLastAccessBackgroundTime(int);
+    method public long getLastAccessForegroundTime(int);
+    method public long getLastAccessTime(int);
+    method public long getLastAccessTime(int, int, int);
+    method public long getLastBackgroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+    method public long getLastDuration(int);
+    method public long getLastDuration(int, int, int);
+    method public long getLastForegroundDuration(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
+    method public long getLastRejectBackgroundTime(int);
+    method public long getLastRejectForegroundTime(int);
+    method public long getLastRejectTime(int);
+    method public long getLastRejectTime(int, int, int);
+    method public boolean isRunning();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedOpEntry> CREATOR;
   }
 
   public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
@@ -311,7 +335,7 @@
   public static final class AppOpsManager.HistoricalOpsRequest.Builder {
     ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
-    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFeatureId(@Nullable String);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
@@ -320,9 +344,9 @@
 
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method @IntRange(from=0) public int getFeatureCount();
-    method @Nullable public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOps(@NonNull String);
-    method @NonNull public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOpsAt(@IntRange(from=0) int);
+    method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@NonNull String);
+    method @NonNull public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOpsAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getAttributedOpsCount();
     method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
     method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
     method @IntRange(from=0) public int getOpCount();
@@ -343,8 +367,8 @@
 
   public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();
     method @Deprecated public long getDuration();
-    method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.OpFeatureEntry> getFeatures();
     method public long getLastAccessBackgroundTime(int);
     method public long getLastAccessForegroundTime(int);
     method public long getLastAccessTime(int);
@@ -374,36 +398,13 @@
 
   public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public String getFeatureId();
+    method @Nullable public String getAttributionTag();
     method @Nullable public String getPackageName();
     method @IntRange(from=0) public int getUid();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
   }
 
-  public static final class AppOpsManager.OpFeatureEntry implements android.os.Parcelable {
-    method public int describeContents();
-    method public long getLastAccessBackgroundTime(int);
-    method public long getLastAccessForegroundTime(int);
-    method public long getLastAccessTime(int);
-    method public long getLastAccessTime(int, int, int);
-    method public long getLastBackgroundDuration(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
-    method public long getLastDuration(int);
-    method public long getLastDuration(int, int, int);
-    method public long getLastForegroundDuration(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
-    method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
-    method public long getLastRejectBackgroundTime(int);
-    method public long getLastRejectForegroundTime(int);
-    method public long getLastRejectTime(int);
-    method public long getLastRejectTime(int, int, int);
-    method public boolean isRunning();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpFeatureEntry> CREATOR;
-  }
-
   public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
@@ -465,7 +466,7 @@
   public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {
     ctor public RuntimeAppOpAccessMessage(@IntRange(from=0L) int, @IntRange(from=0L) int, @NonNull String, @Nullable String, @NonNull String, int);
     method public int describeContents();
-    method @Nullable public String getFeatureId();
+    method @Nullable public String getAttributionTag();
     method @NonNull public String getMessage();
     method @NonNull public String getOp();
     method @NonNull public String getPackageName();
@@ -596,9 +597,22 @@
 package android.app.blob {
 
   public class BlobStoreManager {
+    method @Nullable public android.app.blob.LeaseInfo getLeaseInfo(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
+    method @NonNull public java.util.List<android.app.blob.BlobHandle> getLeasedBlobs() throws java.io.IOException;
     method public void waitForIdle(long) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
   }
 
+  public final class LeaseInfo implements android.os.Parcelable {
+    ctor public LeaseInfo(@NonNull String, long, @IdRes int, @Nullable CharSequence);
+    method public int describeContents();
+    method @Nullable public CharSequence getDescription();
+    method @IdRes public int getDescriptionResId();
+    method public long getExpiryTimeMillis();
+    method @NonNull public String getPackageName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.blob.LeaseInfo> CREATOR;
+  }
+
 }
 
 package android.app.prediction {
@@ -843,6 +857,7 @@
     method @NonNull public android.content.integrity.RuleSet getCurrentRuleSet();
     method @NonNull public String getCurrentRuleSetProvider();
     method @NonNull public String getCurrentRuleSetVersion();
+    method @NonNull public java.util.List<java.lang.String> getWhitelistedRuleProviders();
     method public void updateRuleSet(@NonNull android.content.integrity.RuleSet, @NonNull android.content.IntentSender);
     field public static final String EXTRA_STATUS = "android.content.integrity.extra.STATUS";
     field public static final int STATUS_FAILURE = 1; // 0x1
@@ -919,6 +934,7 @@
   }
 
   public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
+    method public int getAutoRevokePermissionsMode();
     method public int getRollbackDataPolicy();
     method @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions();
   }
@@ -3134,7 +3150,7 @@
 
   public static final class Dataset.Builder {
     ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation);
-    method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
   }
 
   public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -3419,13 +3435,15 @@
 
 package android.service.quickaccesswallet {
 
-  public interface QuickAccessWalletClient {
+  public interface QuickAccessWalletClient extends java.io.Closeable {
     method public void addWalletServiceEventListener(@NonNull android.service.quickaccesswallet.QuickAccessWalletClient.WalletServiceEventListener);
+    method public void addWalletServiceEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.WalletServiceEventListener);
     method @NonNull public static android.service.quickaccesswallet.QuickAccessWalletClient create(@NonNull android.content.Context);
     method @Nullable public android.content.Intent createWalletIntent();
     method @Nullable public android.content.Intent createWalletSettingsIntent();
     method public void disconnect();
     method public void getWalletCards(@NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback);
+    method public void getWalletCards(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback);
     method public boolean isWalletFeatureAvailable();
     method public boolean isWalletFeatureAvailableWhenDeviceLocked();
     method public boolean isWalletServiceAvailable();
@@ -3745,7 +3763,7 @@
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
     method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
-    method public int getEmergencyNumberDbVersion();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getEmergencyNumberDbVersion();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
     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);
@@ -4019,10 +4037,6 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR;
   }
 
-  public class ImsManager {
-    field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
-  }
-
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
@@ -4284,82 +4298,12 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
-    field public static final int KEY_1X_EPDG_TIMER_SEC = 64; // 0x40
-    field public static final int KEY_1X_THRESHOLD = 59; // 0x3b
-    field public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; // 0x32
-    field public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; // 0x0
-    field public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; // 0x35
-    field public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; // 0x31
-    field public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; // 0x30
-    field public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; // 0x1
-    field public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; // 0x2f
-    field public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; // 0x34
-    field public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; // 0x33
-    field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19
-    field public static final int KEY_ENABLE_SILENT_REDIAL = 6; // 0x6
-    field public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; // 0x1f
-    field public static final int KEY_LTE_EPDG_TIMER_SEC = 62; // 0x3e
-    field public static final int KEY_LTE_THRESHOLD_1 = 56; // 0x38
-    field public static final int KEY_LTE_THRESHOLD_2 = 57; // 0x39
-    field public static final int KEY_LTE_THRESHOLD_3 = 58; // 0x3a
-    field public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; // 0x3
-    field public static final int KEY_MOBILE_DATA_ENABLED = 29; // 0x1d
-    field public static final int KEY_MULTIENDPOINT_ENABLED = 65; // 0x41
-    field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13
-    field public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; // 0x12
-    field public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; // 0x14
-    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_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
-    field public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; // 0x22
-    field public static final int KEY_RTP_SPEECH_END_PORT = 36; // 0x24
-    field public static final int KEY_RTP_SPEECH_START_PORT = 35; // 0x23
-    field public static final int KEY_RTT_ENABLED = 66; // 0x42
-    field public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; // 0x2b
-    field public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; // 0x2c
-    field public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; // 0x26
-    field public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; // 0x4
-    field public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; // 0x25
-    field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; // 0x2a
-    field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; // 0x27
-    field public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; // 0x20
-    field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; // 0x2d
-    field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; // 0x28
-    field public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; // 0x2e
-    field public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; // 0x29
-    field public static final int KEY_SIP_SESSION_TIMER_SEC = 2; // 0x2
-    field public static final int KEY_SMS_FORMAT = 13; // 0xd
-    field public static final int KEY_SMS_OVER_IP_ENABLED = 14; // 0xe
-    field public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; // 0x36
-    field public static final int KEY_T1_TIMER_VALUE_MS = 7; // 0x7
-    field public static final int KEY_T2_TIMER_VALUE_MS = 8; // 0x8
-    field public static final int KEY_TF_TIMER_VALUE_MS = 9; // 0x9
-    field public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; // 0x5
-    field public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; // 0x18
-    field public static final int KEY_VIDEO_QUALITY = 55; // 0x37
-    field public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // 0x1c
     field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
     field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
-    field public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; // 0xa
-    field public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; // 0x1e
-    field public static final int KEY_VT_PROVISIONING_STATUS = 11; // 0xb
-    field public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; // 0x3f
-    field public static final int KEY_WIFI_THRESHOLD_A = 60; // 0x3c
-    field public static final int KEY_WIFI_THRESHOLD_B = 61; // 0x3d
-    field public static final int PROVISIONING_RESULT_UNKNOWN = -1; // 0xffffffff
     field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
     field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
-    field public static final int SMS_FORMAT_3GPP = 1; // 0x1
-    field public static final int SMS_FORMAT_3GPP2 = 0; // 0x0
     field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
     field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
-    field public static final int VIDEO_QUALITY_HIGH = 1; // 0x1
-    field public static final int VIDEO_QUALITY_LOW = 0; // 0x0
   }
 
   public static class ProvisioningManager.Callback {
@@ -4368,56 +4312,6 @@
     method public void onProvisioningStringChanged(int, @NonNull String);
   }
 
-  public final class RcsContactUceCapability implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
-    method @NonNull public android.net.Uri getContactUri();
-    method @Nullable public android.net.Uri getServiceUri(long);
-    method public boolean isCapable(long);
-    method public boolean isCapable(@NonNull String);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
-    field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000
-    field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000
-    field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2
-    field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4
-    field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1
-    field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000
-    field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8
-    field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40
-    field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80
-    field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20
-    field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10
-    field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000
-    field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000
-    field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000
-    field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000
-    field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
-    field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
-    field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
-    field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
-    field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
-    field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
-    field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
-    field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000
-    field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000
-    field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
-    field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
-    field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
-    field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
-    field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
-    field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
-  }
-
-  public static class RcsContactUceCapability.Builder {
-    ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability build();
-  }
-
   public class RcsUceAdapter {
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
   }
@@ -4664,24 +4558,12 @@
     method public int transact(android.os.Bundle);
     method public int updateCallBarring(int, int, String[]);
     method public int updateCallBarringForServiceClass(int, int, String[], int);
-    method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
     method public int updateCallForward(int, int, String, int, int);
     method public int updateCallWaiting(boolean, int);
     method public int updateClip(boolean);
     method public int updateClir(int);
     method public int updateColp(boolean);
     method public int updateColr(int);
-    field public static final int CALL_BARRING_ALL = 7; // 0x7
-    field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1
-    field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2
-    field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6
-    field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9
-    field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8
-    field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3
-    field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4
-    field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa
-    field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5
-    field public static final int INVALID_RESULT = -1; // 0xffffffff
   }
 
 }
@@ -4953,8 +4835,8 @@
   }
 
   public class SurfaceControlViewHost {
-    method public void addView(@NonNull android.view.View, android.view.WindowManager.LayoutParams);
     method public void relayout(android.view.WindowManager.LayoutParams);
+    method public void setView(@NonNull android.view.View, @NonNull android.view.WindowManager.LayoutParams);
   }
 
   @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
@@ -4970,7 +4852,7 @@
     method public void resetRtlProperties();
     method public boolean restoreFocusInCluster(int);
     method public boolean restoreFocusNotInCluster();
-    method public void setAutofilled(boolean);
+    method public void setAutofilled(boolean, boolean);
     method public final void setFocusedInCluster();
     method public void setIsRootNamespace(boolean);
     method public final void setShowingLayoutBounds(boolean);
@@ -5084,6 +4966,7 @@
     method public long getEventTime();
     method @Nullable public android.view.autofill.AutofillId getId();
     method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
+    method @Nullable public android.graphics.Insets getInsets();
     method @Nullable public CharSequence getText();
     method public int getType();
     method @Nullable public android.view.contentcapture.ViewNode getViewNode();
@@ -5094,6 +4977,7 @@
     field public static final int TYPE_SESSION_RESUMED = 7; // 0x7
     field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
     field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
+    field public static final int TYPE_VIEW_INSETS_CHANGED = 9; // 0x9
     field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
     field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5
     field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 56f2340..713e923 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -485,7 +485,7 @@
         PackageNotificationChannelGroupPreferences package_notification_channel_group_preferences =
                 10073 [(module) = "framework"];
         GnssStats gnss_stats = 10074 [(module) = "framework"];
-        AppFeaturesOps app_features_ops = 10075 [(module) = "framework"];
+        AttributedAppOps attributed_app_ops = 10075 [(module) = "framework"];
         VoiceCallSession voice_call_session = 10076 [(module) = "telephony"];
         VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
         SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
@@ -3332,16 +3332,12 @@
     optional int32 uid = 1 [(is_uid) = true];
 
     // The operation's name.
-    // To the extent possible, preserve the mapping from AppOpsManager.OP_ constants.
-    // Only these named ops are actually logged.
-    enum AppOpName {
-        OP_NONE = -1; // Also represents UNKNOWN.
-        OP_COARSE_LOCATION = 0;
-        OP_FINE_LOCATION = 1;
-        OP_CAMERA = 26;
-        OP_RECORD_AUDIO = 27;
-    }
-    optional AppOpName app_op_name = 2 [default = OP_NONE];
+    // Only following four ops are logged
+    // COARSE_LOCATION = 0
+    // FINE_LOCATION = 1
+    // CAMERA = 26
+    // RECORD_AUDIO = 27
+    optional android.app.AppOpEnum app_op_name = 2 [default = APP_OP_NONE];
 
     // The uid's permission mode for accessing the AppOp during this fgs session.
     enum Mode {
@@ -7571,8 +7567,8 @@
     // Name of the package performing the op
     optional string package_name = 2;
 
-    // operation id; maps to the OP_* constants in AppOpsManager.java
-    optional int32 op_id = 3;
+    // operation id
+    optional android.app.AppOpEnum op_id = 3 [default = APP_OP_NONE];
 
     // The number of times the op was granted while the app was in the
     // foreground (only for trusted requests)
@@ -7603,21 +7599,22 @@
 }
 
 /**
- * Historical app ops data per package and features.
+ * Historical app ops data per package and attribution tag.
  */
-message AppFeaturesOps {
+message AttributedAppOps {
     // Uid of the package requesting the op
     optional int32 uid = 1 [(is_uid) = true];
 
     // Name of the package performing the op
     optional string package_name = 2;
 
-    // feature id; provided by developer when accessing related API, limited at 50 chars by API.
-    // Features must be provided through manifest using <feature> tag available in R and above.
-    optional string feature_id = 3;
+    // tag; provided by developer when accessing related API, limited at 50 chars by API.
+    // Attributions must be provided through manifest using <attribution> tag available in R and
+    // above.
+    optional string tag = 3;
 
-    // operation id; maps to the OPSTR_* constants in AppOpsManager.java
-    optional string op = 4;
+    // operation id
+    optional android.app.AppOpEnum op = 4 [default = APP_OP_NONE];
 
     // The number of times the op was granted while the app was in the
     // foreground (only for trusted requests)
@@ -8476,9 +8473,11 @@
     // operation string id per OPSTR_ constants in AppOpsManager.java
     optional string op = 3;
 
-    // feature id; provided by developer when accessing related API, limited at 50 chars by API.
-    // Features must be provided through manifest using <feature> tag available in R and above.
-    optional string feature_id = 4;
+    // attribution_tag; provided by developer when accessing related API, limited at 50 chars by
+    // API.
+    // Attributions must be provided through manifest using <attribution> tag available in R and
+    // above.
+    optional string attribution_tag = 4;
 
     // message related to app op access, limited to 600 chars by API
     optional string message = 5;
@@ -8487,6 +8486,7 @@
         DEFAULT = 0;
         UNIFORM = 1;
         RARELY_USED = 2;
+        BOOT_TIME_SAMPLING = 3;
     }
 
     // sampling strategy used to collect this message
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 258f84d..b515d0a 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -350,17 +350,19 @@
     return false;
 }
 
-void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     int32_t value = readNextValue<int32_t>();
     addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
 }
 
-void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     int64_t value = readNextValue<int64_t>();
     addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
 }
 
-void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     int32_t numBytes = readNextValue<int32_t>();
     if ((uint32_t)numBytes > mRemainingLen) {
         mValid = false;
@@ -371,20 +373,23 @@
     mBuf += numBytes;
     mRemainingLen -= numBytes;
     addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
 }
 
-void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     float value = readNextValue<float>();
     addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
 }
 
-void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     // cast to int32_t because FieldValue does not support bools
     int32_t value = (int32_t)readNextValue<uint8_t>();
     addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
 }
 
-void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     int32_t numBytes = readNextValue<int32_t>();
     if ((uint32_t)numBytes > mRemainingLen) {
         mValid = false;
@@ -395,9 +400,10 @@
     mBuf += numBytes;
     mRemainingLen -= numBytes;
     addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
 }
 
-void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
     int32_t numPairs = readNextValue<uint8_t>();
 
     for (pos[1] = 1; pos[1] <= numPairs; pos[1]++) {
@@ -405,56 +411,79 @@
 
         // parse key
         pos[2] = 1;
-        parseInt32(pos, 2, last);
+        parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
 
         // parse value
         last[2] = true;
-        uint8_t typeId = getTypeId(readNextValue<uint8_t>());
-        switch (typeId) {
+
+        uint8_t typeInfo = readNextValue<uint8_t>();
+        switch (getTypeId(typeInfo)) {
             case INT32_TYPE:
                 pos[2] = 2; // pos[2] determined by index of type in KeyValuePair in atoms.proto
-                parseInt32(pos, 2, last);
+                parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
                 break;
             case INT64_TYPE:
                 pos[2] = 3;
-                parseInt64(pos, 2, last);
+                parseInt64(pos, /*depth=*/2, last, /*numAnnotations=*/0);
                 break;
             case STRING_TYPE:
                 pos[2] = 4;
-                parseString(pos, 2, last);
+                parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
                 break;
             case FLOAT_TYPE:
                 pos[2] = 5;
-                parseFloat(pos, 2, last);
+                parseFloat(pos, /*depth=*/2, last, /*numAnnotations=*/0);
                 break;
             default:
                 mValid = false;
         }
     }
 
+    parseAnnotations(numAnnotations);
+
     pos[1] = pos[2] = 1;
     last[1] = last[2] = false;
 }
 
-void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last) {
+void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
+                                     uint8_t numAnnotations) {
     int32_t numNodes = readNextValue<uint8_t>();
     for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
         last[1] = (pos[1] == numNodes);
 
         // parse uid
         pos[2] = 1;
-        parseInt32(pos, 2, last);
+        parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
 
         // parse tag
         pos[2] = 2;
         last[2] = true;
-        parseString(pos, 2, last);
+        parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
     }
 
+    parseAnnotations(numAnnotations);
+
     pos[1] = pos[2] = 1;
     last[1] = last[2] = false;
 }
 
+// TODO(b/151109630): store annotation information within LogEvent
+void LogEvent::parseAnnotations(uint8_t numAnnotations) {
+    for (uint8_t i = 0; i < numAnnotations; i++) {
+        /*uint8_t annotationId = */ readNextValue<uint8_t>();
+        uint8_t annotationType = readNextValue<uint8_t>();
+        switch (annotationType) {
+            case BOOL_TYPE:
+                /*bool annotationValue = */ readNextValue<uint8_t>();
+                break;
+            case INT32_TYPE:
+                /*int32_t annotationValue =*/ readNextValue<int32_t>();
+                break;
+            default:
+                mValid = false;
+        }
+    }
+}
 
 // This parsing logic is tied to the encoding scheme used in StatsEvent.java and
 // stats_event.c
@@ -475,6 +504,7 @@
     typeInfo = readNextValue<uint8_t>();
     if (getTypeId(typeInfo) != INT64_TYPE) mValid = false;
     mElapsedTimestampNs = readNextValue<int64_t>();
+    parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
     numElements--;
 
     typeInfo = readNextValue<uint8_t>();
@@ -484,37 +514,36 @@
 
 
     for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
+        last[0] = (pos[0] == numElements);
+
         typeInfo = readNextValue<uint8_t>();
         uint8_t typeId = getTypeId(typeInfo);
 
-        last[0] = (pos[0] == numElements);
-
         // TODO(b/144373276): handle errors passed to the socket
-        // TODO(b/144373257): parse annotations
         switch(typeId) {
             case BOOL_TYPE:
-                parseBool(pos, 0, last);
+                parseBool(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case INT32_TYPE:
-                parseInt32(pos, 0, last);
+                parseInt32(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case INT64_TYPE:
-                parseInt64(pos, 0, last);
+                parseInt64(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case FLOAT_TYPE:
-                parseFloat(pos, 0, last);
+                parseFloat(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case BYTE_ARRAY_TYPE:
-                parseByteArray(pos, 0, last);
+                parseByteArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case STRING_TYPE:
-                parseString(pos, 0, last);
+                parseString(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case KEY_VALUE_PAIRS_TYPE:
-                parseKeyValuePairs(pos, 0, last);
+                parseKeyValuePairs(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             case ATTRIBUTION_CHAIN_TYPE:
-                parseAttributionChain(pos, 0, last);
+                parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
                 break;
             default:
                 mValid = false;
@@ -531,7 +560,7 @@
 }
 
 uint8_t LogEvent::getNumAnnotations(uint8_t typeInfo) {
-    return (typeInfo >> 4) & 0x0F;
+    return (typeInfo >> 4) & 0x0F; // num annotations in upper 4 bytes
 }
 
 int64_t LogEvent::GetLong(size_t key, status_t* err) const {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index b68eeb8..6537f13 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -232,14 +232,15 @@
      */
     LogEvent(const LogEvent&);
 
-    void parseInt32(int32_t* pos, int32_t depth, bool* last);
-    void parseInt64(int32_t* pos, int32_t depth, bool* last);
-    void parseString(int32_t* pos, int32_t depth, bool* last);
-    void parseFloat(int32_t* pos, int32_t depth, bool* last);
-    void parseBool(int32_t* pos, int32_t depth, bool* last);
-    void parseByteArray(int32_t* pos, int32_t depth, bool* last);
-    void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last);
-    void parseAttributionChain(int32_t* pos, int32_t depth, bool* last);
+    void parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
+    void parseAnnotations(uint8_t numAnnotations);
 
     /**
      * The below three variables are only valid during the execution of
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ca37e9b..2c41e8d 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -269,6 +270,11 @@
     private float mDurationScale = -1f;
 
     /**
+     * Animation handler used to schedule updates for this animation.
+     */
+    private AnimationHandler mAnimationHandler;
+
+    /**
      * Public constants
      */
 
@@ -1684,6 +1690,15 @@
      * @hide
      */
     public AnimationHandler getAnimationHandler() {
-        return AnimationHandler.getInstance();
+        return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance();
+    }
+
+    /**
+     * Sets the animation handler used to schedule updates for this animator or {@code null} to use
+     * the default handler.
+     * @hide
+     */
+    public void setAnimationHandler(@Nullable AnimationHandler animationHandler) {
+        mAnimationHandler = animationHandler;
     }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8d6bc72..6480a6a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5829,7 +5829,7 @@
                 intent.prepareToLeaveProcess(this);
                 result = ActivityTaskManager.getService()
                     .startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
-                            getFeatureId(), intent,
+                            getAttributionTag(), intent,
                             intent.resolveTypeIfNeeded(getContentResolver()), mToken, mEmbeddedID,
                             requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED, null, options);
             } catch (RemoteException e) {
@@ -6624,12 +6624,10 @@
         String packageName = getPackageName();
         try {
             data.prepareToLeaveProcess(this);
-            IIntentSender target =
-                ActivityManager.getService().getIntentSenderWithFeature(
-                        ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, getFeatureId(),
-                        mParent == null ? mToken : mParent.mToken,
-                        mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null,
-                        getUserId());
+            IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature(
+                    ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, getAttributionTag(),
+                    mParent == null ? mToken : mParent.mToken, mEmbeddedID, requestCode,
+                    new Intent[]{data}, null, flags, null, getUserId());
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
             // Empty
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index dd4788e..1a92b75 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4243,6 +4243,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION)
     public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) {
         if (mcc == null || mnc == null) {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index ec11043..489a0de 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -34,6 +34,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Activity manager local system service interface.
@@ -124,6 +125,12 @@
     public abstract int getUidProcessState(int uid);
 
     /**
+     * Get a map of pid and package name that process of that pid Android/data and Android/obb
+     * directory is not mounted to lowerfs.
+     */
+    public abstract Map<Integer, String> getProcessesWithPendingBindMounts(int userId);
+
+    /**
      * @return {@code true} if system is ready, {@code false} otherwise.
      */
     public abstract boolean isSystemReady();
diff --git a/core/java/android/app/AppOps.md b/core/java/android/app/AppOps.md
new file mode 100644
index 0000000..bee701a
--- /dev/null
+++ b/core/java/android/app/AppOps.md
@@ -0,0 +1,212 @@
+<!--
+  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
+  -->
+
+# App-ops
+
+App-ops are used for two purposes: Access control and tracking.
+
+App-ops cover a wide variety of functionality from helping with runtime permissions to battery
+consumption tracking.
+
+App-ops are defined in `AppOpsManager` as `OP_...` and need to be continuously numbered. The
+integer values of the app-ops are not exposed. For app-ops visible to 3rd party apps,
+the name of the app-op might be exposed as `OPSTR_`. As the integers are not part of the API, they
+might (and have) changed between platform versions and OEM implementations.
+`AppOpsManager.opToPublicName` and `AppOpsManager.strOpToOp` allow for conversion between integer
+and string identifier for the op.
+
+## App-ops as access restrictions
+
+App-ops can either be controlled for each [uid](../os/Users.md#int-uid) or for each package. Which
+one is used depends on the API provider maintaining this app-op.
+
+For any security or privacy related app-ops the provider needs to control the app-op per uid
+as all security and privacy is based on uid in Android.
+
+App-op used for non-security related tasks are usually controlled per package to provide finer
+granularity.
+
+### Setting the app-op mode
+
+To control access the app-op can be set to:
+
+`MODE_DEFAULT`
+: Default behavior, might differ from app-op to app-op
+
+`MODE_ALLOWED`
+: Allow the access
+
+`MODE_FOREGROUND`
+: Allow the access but only if the app is currently in the [foreground](#foreground)
+
+`MODE_IGNORED`
+: Don't allow the access, i.e. don't perform the requested action or return dummy data
+
+`MODE_ERRORED`
+: Throw a `SecurityException` on access. This can be suppressed by using a `...noThrow` method to
+check the mode
+
+The initial state of an app-op is defined in `AppOpsManager.sOpDefaultMode`. Confusingly the
+initial state is often not `MODE_DEFAULT`
+
+Per-package modes can be set using `AppOpsManager.setMode` and per-uid modes can be set using
+`AppOpsManager.setUidMode`.
+
+**Warning**: Do not use `setMode` and `setUidMode` for the same app-op. Due to the way the
+internal storage for the mode works this can lead to very confusing behavior. If this ever happened
+by accident this needs to be cleaned up for any affected user as the app-op mode is retained over
+reboot.
+
+App-ops can also be set via the shell using the `appops set` command. The target package/uid can be
+defined via parameters to this command.
+
+The current state of the app-op can be read via the `appops get` command or via `dumpsys appops`.
+If the app-op is not mentioned in the output the app-op is in it's initial state.
+
+For example `dumpsys appops`:
+```
+[...]
+  Uid 2000:
+    [...]
+      COARSE_LOCATION: mode=foreground
+      START_FOREGROUND: mode=foreground
+      LEGACY_STORAGE: mode=ignore
+    [...]
+```
+
+### Guarding access based on app-ops
+
+API providers need to check the mode returned by `AppOpsManager.noteOp` if they are are allowing
+access to operations gated by the app-op. `AppOpsManager.unsafeCheckOp` should be used to check the
+mode if no access is granted. E.g. this can be for displaying app-op state in the UI or when
+checking the state before later calling `noteOp` anyway.
+
+If an operation refers to a time span (e.g. a audio-recording session) the API provider should
+use `AppOpsManager.startOp` and `AppOpsManager.finishOp` instead of `noteOp`.
+
+`noteOp` and `startOp` take a `packageName` and `featureId` parameter. These need to be read from
+the calling apps context as `Context.getOpPackageName` and `Context.getFeatureId`, then send to
+the data provider and then passed on the `noteOp`/`startOp` method.
+
+#### App-ops and permissions
+
+Access guarding is often done in combination with permissions using [runtime permissions
+](../permission/Permissions.md#runtime-permissions-and-app-ops) or [app-op permissions
+](../permission/Permissions.md#app-op-permissions). This is preferred over just using an app-op
+ as permissions a concept more familiar to app developers.
+
+### Foreground
+
+The `AppOpsService` tracks the apps' proc state (== foreground-ness) by following the
+`ActivityManagerService`'s proc state. It reduces the possible proc states to only those needed
+for app-ops. It also delays the changes by a _settle time_. This delay is needed as the proc state
+can fluctuate when switching apps. By delaying the change the appops service is not affected by
+those.
+
+The proc state is used for two use cases: Firstly, Tracking remembers the proc state for each
+tracked event. Secondly, `noteOp`/`checkOp` calls for app-op that are set to `MODE_FOREGROUND` are
+translated using the `AppOpsService.UidState.evalMode` method into `MODE_ALLOWED` when the app is
+counted as foreground and `MODE_IGNORED` when the app is counted as background. `checkOpRaw`
+calls are not affected.
+
+The current proc state for an app can be read from `dumpsys appops`. The tracking information can
+be read from `dumpsys appops`
+
+```
+Uid u0a118:
+  state=fg
+  capability=6
+```
+
+## App-ops for tracking
+
+App-ops track many important events, including all accesses to runtime permission protected
+APIs. This is done by tracking when an app-op was noted or started. The tracked data can only be
+read by system components.
+
+**Note:** Only `noteOp`/`startOp` calls are tracked; `unsafeCheckOp` is not tracked. Hence it is
+important to eventually call `noteOp` or `startOp` when providing access to protected operations
+or data.
+
+Some apps are forwarding access to other apps. E.g. an app might get the location from the
+system's location provider and then send the location further to a 3rd app. In this case the
+app passing on the data needs to call `AppOpsManager.noteProxyOp` to signal the access proxying.
+This might also make sense inside of a single app if the access is forwarded between two features of
+the app. In this case an app-op is noted for the forwarding app (proxy) and the app that received
+the data (proxied). As any app can do it is important to track how much the system trusts this
+proxy-access-tracking. For more details see `AppOpService.noteProxyOperation`.
+
+The tracking information can be read from `dumpsys appops` split by feature, proc state and
+proxying information with the syntax
+
+```
+Package THE_PACKAGE_NAME:
+  AN_APP_OP (CURRENT_MODE):
+    FEATURE_ID (or null for default feature)=[
+      ACCESS_OR_REJECT: [PROC_STATE-PROXYING_TAG] TIME proxy[INFO_ABOUT_PROXY IF_PROXY_ACCESS]
+```
+
+Example:
+
+```
+Package com.google.android.gms:
+  READ_CONTACTS (allow):
+    null=[
+      Access: [fgsvc-s] 2020-02-14 14:24:10.559 (-3d23h15m43s642ms)
+      Access: [fgsvc-tp] 2020-02-14 14:23:58.189 (-3d23h15m56s12ms)
+    ]
+    apkappcontext=[
+      Access: [fg-tp] 2020-02-17 14:24:54.721 (-23h14m59s480ms)
+    ]
+    com.google.android.gms.icing=[
+      Access: [fgsvc-tpd] 2020-02-14 14:26:27.018 (-3d23h13m27s183ms) proxy[uid=10070, pkg=com.android.providers.contacts, feature=null]
+      Access: [fg-tpd] 2020-02-18 02:26:08.711 (-11h13m45s490ms) proxy[uid=10070, pkg=com.android.providers.contacts, feature=null]
+      Access: [bg-tpd] 2020-02-14 14:34:55.310 (-3d23h4m58s891ms) proxy[uid=10070, pkg=com.android.providers.contacts, feature=null]
+    ]
+  MANAGE_EXTERNAL_STORAGE (default):
+    null=[
+      Reject: [fg-s]2020-02-18 08:00:04.444 (-5h39m49s757ms)
+      Reject: [bg-s]2020-02-18 08:00:04.427 (-5h39m49s774ms)
+    ]
+```
+
+### Tracking an app's own private data accesses
+
+An app can register an `AppOpsManager.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.
+
+## Listening to app-op events
+
+System apps (with the appropriate permissions) can listen to most app-op events, such as
+
+`noteOp`
+: `startWatchingNoted`
+
+`startOp`/`finishOp`
+: `startWatchingActive`
+
+mode changes
+: `startWatchingMode`
+
+[foreground](#foreground)-ness changes
+: `startWatchingMode` using the `WATCH_FOREGROUND_CHANGES` flag
+
+Watching such events is only ever as good as the tracked events. E.g. if the audio provider does
+not call `startOp` for a audio-session, the app's activeness for the record-audio app-op is not
+changed. Further there were cases where app-ops were noted even though no data was accessed or
+operation was performed. Hence before relying on the data from app-ops, double check if the data
+is actually reliable.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 9925d69..fa4aa19 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -160,8 +160,8 @@
  * <p>Some apps are forwarding access to other apps. E.g. an app might get the location from the
  * system's location provider and then send the location further to a 3rd app. In this case the
  * app passing on the data needs to call {@link #noteProxyOp} to signal the access proxying. This
- * might also make sense inside of a single app if the access is forwarded between two features of
- * the app.
+ * might also make sense inside of a single app if the access is forwarded between two parts of
+ * the tagged with different attribution tags.
  *
  * <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
@@ -696,6 +696,10 @@
     public static final int SAMPLING_STRATEGY_RARELY_USED =
             FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
 
+    /** @hide */
+    public static final int SAMPLING_STRATEGY_BOOT_TIME_SAMPLING =
+            FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__BOOT_TIME_SAMPLING;
+
     /**
      * Strategies used for message sampling
      * @hide
@@ -704,7 +708,8 @@
     @IntDef(prefix = {"SAMPLING_STRATEGY_"}, value = {
             SAMPLING_STRATEGY_DEFAULT,
             SAMPLING_STRATEGY_UNIFORM,
-            SAMPLING_STRATEGY_RARELY_USED
+            SAMPLING_STRATEGY_RARELY_USED,
+            SAMPLING_STRATEGY_BOOT_TIME_SAMPLING
     })
     public @interface SamplingStrategy {}
 
@@ -1071,9 +1076,17 @@
     /** @hide Auto-revoke app permissions if app is unused for an extended period */
     public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
 
+    /**
+     * Whether {@link #OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED} is allowed to be changed by
+     * the installer
+     *
+     * @hide
+     */
+    public static final int OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98;
+
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 98;
+    public static final int _NUM_OP = 99;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1356,7 +1369,6 @@
     @SystemApi
     public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
     /** @hide Read device identifiers */
-    @SystemApi
     public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
     /** @hide Query all packages on device */
     public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages";
@@ -1373,6 +1385,10 @@
     public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED =
             "android:auto_revoke_permissions_if_unused";
 
+    /** @hide Auto-revoke app permissions if app is unused for an extended period */
+    public static final String OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER =
+            "android:auto_revoke_managed_by_installer";
+
     /** @hide Communicate cross-profile within the same profile group. */
     @SystemApi
     public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
@@ -1463,6 +1479,7 @@
             OP_LOADER_USAGE_STATS,
             OP_ACCESS_CALL_AUDIO,
             OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+            OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
     };
 
     /**
@@ -1572,6 +1589,7 @@
             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
+            OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
 
     /**
@@ -1676,6 +1694,7 @@
             OPSTR_LOADER_USAGE_STATS,
             OPSTR_ACCESS_CALL_AUDIO,
             OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+            OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER,
     };
 
     /**
@@ -1781,6 +1800,7 @@
             "LOADER_USAGE_STATS",
             "ACCESS_CALL_AUDIO",
             "AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
+            "AUTO_REVOKE_MANAGED_BY_INSTALLER",
     };
 
     /**
@@ -1887,6 +1907,7 @@
             android.Manifest.permission.LOADER_USAGE_STATS,
             Manifest.permission.ACCESS_CALL_AUDIO,
             null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+            null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
 
     /**
@@ -1993,6 +2014,7 @@
             null, // LOADER_USAGE_STATS
             null, // ACCESS_CALL_AUDIO
             null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+            null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
 
     /**
@@ -2098,6 +2120,7 @@
             null, // LOADER_USAGE_STATS
             null, // ACCESS_CALL_AUDIO
             null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+            null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
 
     /**
@@ -2202,6 +2225,7 @@
             AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
             AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO
             AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+            AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
 
     /**
@@ -2310,9 +2334,118 @@
             false, // LOADER_USAGE_STATS
             false, // ACCESS_CALL_AUDIO
             false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+            false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
 
     /**
+     * This maps each operation to its statsd logging code.
+     */
+    private static int[] sOpToLoggingId = new int[]{
+            AppProtoEnums.APP_OP_COARSE_LOCATION, // OP_COARSE_LOCATION
+            AppProtoEnums.APP_OP_FINE_LOCATION, // OP_FINE_LOCATION
+            AppProtoEnums.APP_OP_GPS, // OP_ID__GPS
+            AppProtoEnums.APP_OP_VIBRATE, // OP_VIBRATE
+            AppProtoEnums.APP_OP_READ_CONTACTS, // OP_READ_CONTACTS
+            AppProtoEnums.APP_OP_WRITE_CONTACTS, // OP_WRITE_CONTACTS
+            AppProtoEnums.APP_OP_READ_CALL_LOG, // OP_READ_CALL_LOG
+            AppProtoEnums.APP_OP_WRITE_CALL_LOG, // OP_WRITE_CALL_LOG
+            AppProtoEnums.APP_OP_READ_CALENDAR, // OP_READ_CALENDAR
+            AppProtoEnums.APP_OP_WRITE_CALENDAR, // OP_WRITE_CALENDAR
+            AppProtoEnums.APP_OP_WIFI_SCAN, // OP_WIFI_SCAN
+            AppProtoEnums.APP_OP_POST_NOTIFICATION, // OP_POST_NOTIFICATION
+            AppProtoEnums.APP_OP_NEIGHBORING_CELLS, // OP_NEIGHBORING_CELLS
+            AppProtoEnums.APP_OP_CALL_PHONE, // OP_CALL_PHONE
+            AppProtoEnums.APP_OP_READ_SMS, // OP_READ_SMS
+            AppProtoEnums.APP_OP_WRITE_SMS, // OP_WRITE_SMS
+            AppProtoEnums.APP_OP_RECEIVE_SMS, // OP_RECEIVE_SMS
+            AppProtoEnums.APP_OP_RECEIVE_EMERGENCY_SMS, // OP_RECEIVE_EMERGENCY_SMS
+            AppProtoEnums.APP_OP_RECEIVE_MMS, // OP_RECEIVE_MMS
+            AppProtoEnums.APP_OP_RECEIVE_WAP_PUSH, // OP_RECEIVE_WAP_PUSH
+            AppProtoEnums.APP_OP_SEND_SMS, // OP_SEND_SMS
+            AppProtoEnums.APP_OP_READ_ICC_SMS, // OP_READ_ICC_SMS
+            AppProtoEnums.APP_OP_WRITE_ICC_SMS, // OP_WRITE_ICC_SMS
+            AppProtoEnums.APP_OP_WRITE_SETTINGS, // OP_WRITE_SETTINGS
+            AppProtoEnums.APP_OP_SYSTEM_ALERT_WINDOW, // OP_SYSTEM_ALERT_WINDOW
+            AppProtoEnums.APP_OP_ACCESS_NOTIFICATIONS, // OP_ACCESS_NOTIFICATIONS
+            AppProtoEnums.APP_OP_CAMERA, // OP_CAMERA
+            AppProtoEnums.APP_OP_RECORD_AUDIO, // OP_RECORD_AUDIO
+            AppProtoEnums.APP_OP_PLAY_AUDIO, // OP_PLAY_AUDIO
+            AppProtoEnums.APP_OP_READ_CLIPBOARD, // OP_READ_CLIPBOARD
+            AppProtoEnums.APP_OP_WRITE_CLIPBOARD, // OP_WRITE_CLIPBOARD
+            AppProtoEnums.APP_OP_TAKE_MEDIA_BUTTONS, // OP_TAKE_MEDIA_BUTTONS
+            AppProtoEnums.APP_OP_TAKE_AUDIO_FOCUS, // OP_TAKE_AUDIO_FOCUS
+            AppProtoEnums.APP_OP_AUDIO_MASTER_VOLUME, // OP_AUDIO_MASTER_VOLUME
+            AppProtoEnums.APP_OP_AUDIO_VOICE_VOLUME, // OP_AUDIO_VOICE_VOLUME
+            AppProtoEnums.APP_OP_AUDIO_RING_VOLUME, // OP_AUDIO_RING_VOLUME
+            AppProtoEnums.APP_OP_AUDIO_MEDIA_VOLUME, // OP_AUDIO_MEDIA_VOLUME
+            AppProtoEnums.APP_OP_AUDIO_ALARM_VOLUME, // OP_AUDIO_ALARM_VOLUME
+            AppProtoEnums.APP_OP_AUDIO_NOTIFICATION_VOLUME, // OP_AUDIO_NOTIFICATION_VOLUME
+            AppProtoEnums.APP_OP_AUDIO_BLUETOOTH_VOLUME, // OP_AUDIO_BLUETOOTH_VOLUME
+            AppProtoEnums.APP_OP_WAKE_LOCK, // OP_WAKE_LOCK
+            AppProtoEnums.APP_OP_MONITOR_LOCATION, // OP_MONITOR_LOCATION
+            AppProtoEnums.APP_OP_MONITOR_HIGH_POWER_LOCATION, // OP_MONITOR_HIGH_POWER_LOCATION
+            AppProtoEnums.APP_OP_GET_USAGE_STATS, // OP_GET_USAGE_STATS
+            AppProtoEnums.APP_OP_MUTE_MICROPHONE, //OP_MUTE_MICROPHONE
+            AppProtoEnums.APP_OP_TOAST_WINDOW, // OP_TOAST_WINDOW
+            AppProtoEnums.APP_OP_PROJECT_MEDIA, // OP_PROJECT_MEDIA
+            AppProtoEnums.APP_OP_ACTIVATE_VPN, // OP_ACTIVATE_VPN
+            AppProtoEnums.APP_OP_WRITE_WALLPAPER, // OP_WRITE_WALLPAPER
+            AppProtoEnums.APP_OP_ASSIST_STRUCTURE, // OP_ASSIST_STRUCTURE
+            AppProtoEnums.APP_OP_ASSIST_SCREENSHOT, // OP_ASSIST_SCREENSHOT
+            AppProtoEnums.APP_OP_READ_PHONE_STATE, // OP_READ_PHONE_STATE
+            AppProtoEnums.APP_OP_ADD_VOICEMAIL, // OP_ADD_VOICEMAIL
+            AppProtoEnums.APP_OP_USE_SIP, // OP_USE_SIP
+            AppProtoEnums.APP_OP_PROCESS_OUTGOING_CALLS, // OP_PROCESS_OUTGOING_CALLS
+            AppProtoEnums.APP_OP_USE_FINGERPRINT, // OP_USE_FINGERPRINT
+            AppProtoEnums.APP_OP_BODY_SENSORS, // OP_BODY_SENSORS
+            AppProtoEnums.APP_OP_READ_CELL_BROADCASTS, // OP_READ_CELL_BROADCASTS
+            AppProtoEnums.APP_OP_MOCK_LOCATION, // OP_MOCK_LOCATION
+            AppProtoEnums.APP_OP_READ_EXTERNAL_STORAGE, // OP_READ_EXTERNAL_STORAGE
+            AppProtoEnums.APP_OP_WRITE_EXTERNAL_STORAGE, // OP_WRITE_EXTERNAL_STORAGE
+            AppProtoEnums.APP_OP_TURN_SCREEN_ON, // OP_TURN_SCREEN_ON
+            AppProtoEnums.APP_OP_GET_ACCOUNTS, // OP_GET_ACCOUNTS
+            AppProtoEnums.APP_OP_RUN_IN_BACKGROUND, // OP_RUN_IN_BACKGROUND
+            AppProtoEnums.APP_OP_AUDIO_ACCESSIBILITY_VOLUME, // OP_AUDIO_ACCESSIBILITY_VOLUME
+            AppProtoEnums.APP_OP_READ_PHONE_NUMBERS, // OP_READ_PHONE_NUMBERS
+            AppProtoEnums.APP_OP_REQUEST_INSTALL_PACKAGES, // OP_REQUEST_INSTALL_PACKAGES
+            AppProtoEnums.APP_OP_PICTURE_IN_PICTURE, // OP_PICTURE_IN_PICTURE
+            AppProtoEnums.APP_OP_INSTANT_APP_START_FOREGROUND, // OP_INSTANT_APP_START_FOREGROUND
+            AppProtoEnums.APP_OP_ANSWER_PHONE_CALLS, // OP_ANSWER_PHONE_CALLS
+            AppProtoEnums.APP_OP_RUN_ANY_IN_BACKGROUND, // OP_RUN_ANY_IN_BACKGROUND
+            AppProtoEnums.APP_OP_CHANGE_WIFI_STATE, // OP_CHANGE_WIFI_STATE
+            AppProtoEnums.APP_OP_REQUEST_DELETE_PACKAGES, // OP_REQUEST_DELETE_PACKAGES
+            AppProtoEnums.APP_OP_BIND_ACCESSIBILITY_SERVICE, // OP_BIND_ACCESSIBILITY_SERVICE
+            AppProtoEnums.APP_OP_ACCEPT_HANDOVER, // OP_ACCEPT_HANDOVER
+            AppProtoEnums.APP_OP_MANAGE_IPSEC_TUNNELS, // OP_MANAGE_IPSEC_TUNNELS
+            AppProtoEnums.APP_OP_START_FOREGROUND, // OP_START_FOREGROUND
+            AppProtoEnums.APP_OP_BLUETOOTH_SCAN, // OP_BLUETOOTH_SCAN
+            AppProtoEnums.APP_OP_USE_BIOMETRIC, // OP_USE_BIOMETRIC
+            AppProtoEnums.APP_OP_ACTIVITY_RECOGNITION, // OP_ACTIVITY_RECOGNITION
+            AppProtoEnums.APP_OP_SMS_FINANCIAL_TRANSACTIONS, // OP_SMS_FINANCIAL_TRANSACTIONS
+            AppProtoEnums.APP_OP_READ_MEDIA_AUDIO, // OP_READ_MEDIA_AUDIO
+            AppProtoEnums.APP_OP_WRITE_MEDIA_AUDIO, // OP_WRITE_MEDIA_AUDIO
+            AppProtoEnums.APP_OP_READ_MEDIA_VIDEO, // OP_READ_MEDIA_VIDEO
+            AppProtoEnums.APP_OP_WRITE_MEDIA_VIDEO, // OP_WRITE_MEDIA_VIDEO
+            AppProtoEnums.APP_OP_READ_MEDIA_IMAGES, // OP_READ_MEDIA_IMAGES
+            AppProtoEnums.APP_OP_WRITE_MEDIA_IMAGES, // OP_WRITE_MEDIA_IMAGES
+            AppProtoEnums.APP_OP_LEGACY_STORAGE, // OP_LEGACY_STORAGE
+            AppProtoEnums.APP_OP_ACCESS_ACCESSIBILITY, // OP_ACCESS_ACCESSIBILITY
+            AppProtoEnums.APP_OP_READ_DEVICE_IDENTIFIERS, // OP_READ_DEVICE_IDENTIFIERS
+            AppProtoEnums.APP_OP_ACCESS_MEDIA_LOCATION, // OP_ACCESS_MEDIA_LOCATION
+            AppProtoEnums.APP_OP_QUERY_ALL_PACKAGES, // OP_QUERY_ALL_PACKAGES
+            AppProtoEnums.APP_OP_MANAGE_EXTERNAL_STORAGE, // OP_MANAGE_EXTERNAL_STORAGE
+            AppProtoEnums.APP_OP_INTERACT_ACROSS_PROFILES, // OP_INTERACT_ACROSS_PROFILES
+            AppProtoEnums.APP_OP_ACTIVATE_PLATFORM_VPN, // OP_ACTIVATE_PLATFORM_VPN
+            AppProtoEnums.APP_OP_LOADER_USAGE_STATS, // OP_LOADER_USAGE_STATS
+            AppProtoEnums.APP_OP_ACCESS_CALL_AUDIO, // OP_ACCESS_CALL_AUDIO
+            AppProtoEnums.APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+            // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+            AppProtoEnums.APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER 
+            //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
+    };
+
+
+    /**
      * Mapping from an app op name to the app op code.
      */
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<>();
@@ -2353,6 +2486,10 @@
             throw new IllegalStateException("sOpToString length " + sOpToString.length
                     + " should be " + _NUM_OP);
         }
+        if (sOpToLoggingId.length != _NUM_OP) {
+            throw new IllegalStateException("sOpToLoggingId length " + sOpToLoggingId.length
+                    + " should be " + _NUM_OP);
+        }
         if (sOpNames.length != _NUM_OP) {
             throw new IllegalStateException("sOpNames length " + sOpNames.length
                     + " should be " + _NUM_OP);
@@ -2437,6 +2574,15 @@
     }
 
     /**
+     * Retrieve a logging id for the operation.
+     *
+     * @hide
+     */
+    public static int opToLoggingId(int op) {
+        return sOpToLoggingId[op];
+    }
+
+    /**
      * @hide
      */
     public static int strDebugOpToOp(String op) {
@@ -2658,23 +2804,23 @@
         private @IntRange(from = 0) int mUid;
         /** Package of the proxy that noted the op */
         private @Nullable String mPackageName;
-        /** ID of the feature of the proxy that noted the op */
-        private @Nullable String mFeatureId;
+        /** Attribution tag of the proxy that noted the op */
+        private @Nullable String mAttributionTag;
 
         /**
          * Reinit existing object with new state.
          *
          * @param uid UID of the proxy app that noted the op
          * @param packageName Package of the proxy that noted the op
-         * @param featureId ID of the feature of the proxy that noted the op
+         * @param attributionTag attribution tag of the proxy that noted the op
          *
          * @hide
          */
         public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
-                @Nullable String featureId) {
+                @Nullable String attributionTag) {
             mUid = Preconditions.checkArgumentNonnegative(uid);
             mPackageName = packageName;
-            mFeatureId = featureId;
+            mAttributionTag = attributionTag;
         }
 
 
@@ -2699,21 +2845,21 @@
          *   UID of the proxy app that noted the op
          * @param packageName
          *   Package of the proxy that noted the op
-         * @param featureId
-         *   ID of the feature of the proxy that noted the op
+         * @param attributionTag
+         *   Attribution tag of the proxy that noted the op
          * @hide
          */
         @DataClass.Generated.Member
         public OpEventProxyInfo(
                 @IntRange(from = 0) int uid,
                 @Nullable String packageName,
-                @Nullable String featureId) {
+                @Nullable String attributionTag) {
             this.mUid = uid;
             com.android.internal.util.AnnotationValidations.validate(
                     IntRange.class, null, mUid,
                     "from", 0);
             this.mPackageName = packageName;
-            this.mFeatureId = featureId;
+            this.mAttributionTag = attributionTag;
 
             // onConstructed(); // You can define this method to get a callback
         }
@@ -2727,7 +2873,7 @@
         public OpEventProxyInfo(@NonNull OpEventProxyInfo orig) {
             mUid = orig.mUid;
             mPackageName = orig.mPackageName;
-            mFeatureId = orig.mFeatureId;
+            mAttributionTag = orig.mAttributionTag;
         }
 
         /**
@@ -2747,11 +2893,11 @@
         }
 
         /**
-         * ID of the feature of the proxy that noted the op
+         * Attribution tag of the proxy that noted the op
          */
         @DataClass.Generated.Member
-        public @Nullable String getFeatureId() {
-            return mFeatureId;
+        public @Nullable String getAttributionTag() {
+            return mAttributionTag;
         }
 
         @Override
@@ -2762,11 +2908,11 @@
 
             byte flg = 0;
             if (mPackageName != null) flg |= 0x2;
-            if (mFeatureId != null) flg |= 0x4;
+            if (mAttributionTag != null) flg |= 0x4;
             dest.writeByte(flg);
             dest.writeInt(mUid);
             if (mPackageName != null) dest.writeString(mPackageName);
-            if (mFeatureId != null) dest.writeString(mFeatureId);
+            if (mAttributionTag != null) dest.writeString(mAttributionTag);
         }
 
         @Override
@@ -2783,14 +2929,14 @@
             byte flg = in.readByte();
             int uid = in.readInt();
             String packageName = (flg & 0x2) == 0 ? null : in.readString();
-            String featureId = (flg & 0x4) == 0 ? null : in.readString();
+            String attributionTag = (flg & 0x4) == 0 ? null : in.readString();
 
             this.mUid = uid;
             com.android.internal.util.AnnotationValidations.validate(
                     IntRange.class, null, mUid,
                     "from", 0);
             this.mPackageName = packageName;
-            this.mFeatureId = featureId;
+            this.mAttributionTag = attributionTag;
 
             // onConstructed(); // You can define this method to get a callback
         }
@@ -2814,7 +2960,7 @@
                 time = 1576814974615L,
                 codegenVersion = "1.0.14",
                 sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
-                inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mFeatureId\npublic  void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
+                inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\npublic  void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
         @Deprecated
         private void __metadata() {}
         */
@@ -3013,7 +3159,7 @@
 
     /**
      * Last {@link #noteOp} and {@link #startOp} events performed for a single op and a specific
-     * {@link Context#createFeatureContext(String) feature} for all uidModes and opFlags.
+     * {@link Context#createAttributionContext(String) attribution} for all uidModes and opFlags.
      *
      * @hide
      */
@@ -3022,7 +3168,7 @@
     @Immutable
     // @DataClass(genHiddenConstructor = true) codegen verifier is broken
     @DataClass.Suppress({"getAccessEvents", "getRejectEvents", "getOp"})
-    public static final class OpFeatureEntry implements Parcelable {
+    public static final class AttributedOpEntry implements Parcelable {
         /** The code of the op */
         private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
         /** Whether the op is running */
@@ -3321,8 +3467,8 @@
         }
 
         /**
-         * Gets the proxy info of the app that performed the last access on behalf of this feature
-         * and as a result blamed the op on this app.
+         * Gets the proxy info of the app that performed the last access on behalf of this
+         * attribution and as a result blamed the op on this attribution.
          *
          * @param flags The op flags
          *
@@ -3339,7 +3485,7 @@
 
         /**
          * Gets the proxy info of the app that performed the last foreground access on behalf of
-         * this feature and as a result blamed the op on this app.
+         * this attribution and as a result blamed the op on this attribution.
          *
          * @param flags The op flags
          *
@@ -3357,7 +3503,7 @@
 
         /**
          * Gets the proxy info of the app that performed the last background access on behalf of
-         * this feature and as a result blamed the op on this app.
+         * this attribution and as a result blamed the op on this attribution.
          *
          * @param flags The op flags
          *
@@ -3374,8 +3520,8 @@
         }
 
         /**
-         * Gets the proxy info of the app that performed the last access on behalf of this feature
-         * and as a result blamed the op on this app.
+         * Gets the proxy info of the app that performed the last access on behalf of this
+         * attribution and as a result blamed the op on this attribution.
          *
          * @param fromUidState The lowest UID state for which to query
          * @param toUidState The highest UID state for which to query (inclusive)
@@ -3450,7 +3596,7 @@
 
 
         /**
-         * Creates a new OpFeatureEntry.
+         * Creates a new OpAttributionEntry.
          *
          * @param op
          *   The code of the op
@@ -3463,7 +3609,7 @@
          * @hide
          */
         @DataClass.Generated.Member
-        public OpFeatureEntry(
+        public AttributedOpEntry(
                 @IntRange(from = 0, to = _NUM_OP - 1) int op,
                 boolean running,
                 @Nullable LongSparseArray<NoteOpEvent> accessEvents,
@@ -3533,7 +3679,7 @@
         /** @hide */
         @SuppressWarnings({"unchecked", "RedundantCast"})
         @DataClass.Generated.Member
-        /* package-private */ OpFeatureEntry(@NonNull Parcel in) {
+        /* package-private */ AttributedOpEntry(@NonNull Parcel in) {
             // You can override field unparcelling by defining methods like:
             // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -3556,16 +3702,16 @@
         }
 
         @DataClass.Generated.Member
-        public static final @NonNull Parcelable.Creator<OpFeatureEntry> CREATOR
-                = new Parcelable.Creator<OpFeatureEntry>() {
+        public static final @NonNull Parcelable.Creator<AttributedOpEntry> CREATOR
+                = new Parcelable.Creator<AttributedOpEntry>() {
             @Override
-            public OpFeatureEntry[] newArray(int size) {
-                return new OpFeatureEntry[size];
+            public AttributedOpEntry[] newArray(int size) {
+                return new AttributedOpEntry[size];
             }
 
             @Override
-            public OpFeatureEntry createFromParcel(@NonNull Parcel in) {
-                return new OpFeatureEntry(in);
+            public AttributedOpEntry createFromParcel(@NonNull Parcel in) {
+                return new AttributedOpEntry(in);
             }
         };
 
@@ -3574,7 +3720,7 @@
                 time = 1574809856239L,
                 codegenVersion = "1.0.14",
                 sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
-                inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final  boolean mRunning\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mAccessEvents\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mRejectEvents\npublic @android.annotation.NonNull android.util.ArraySet<java.lang.Long> collectKeys()\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic  long getAccessTime(int,int)\npublic  long getRejectTime(int,int)\npublic  long getDuration(int,int)\npublic  int getProxyUid(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyFeatureId(int,int)\nclass OpFeatureEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+                inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final  boolean mRunning\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpAttributionEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mAccessEvents\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpAttributionEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mRejectEvents\npublic @android.annotation.NonNull android.util.ArraySet<java.lang.Long> collectKeys()\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic  long getAccessTime(int,int)\npublic  long getRejectTime(int,int)\npublic  long getDuration(int,int)\npublic  int getProxyUid(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyAttributionTag(int,int)\nclass OpAttributionEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
         @Deprecated
         private void __metadata() {}
          */
@@ -3600,8 +3746,8 @@
         private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
         /** The mode of the op */
         private final @Mode int mMode;
-        /** The features that have been used when checking the op */
-        private final @NonNull Map<String, OpFeatureEntry> mFeatures;
+        /** The attributed entries by attribution tag */
+        private final @NonNull Map<String, AttributedOpEntry> mAttributedOpEntries;
 
         /**
          * @hide
@@ -3642,7 +3788,7 @@
          * @see #getLastAccessForegroundTime(int)
          * @see #getLastAccessBackgroundTime(int)
          * @see #getLastAccessTime(int, int, int)
-         * @see OpFeatureEntry#getLastAccessTime(int)
+         * @see AttributedOpEntry#getLastAccessTime(int)
          */
         public long getLastAccessTime(@OpFlags int flags) {
             return getLastAccessTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3659,7 +3805,7 @@
          * @see #getLastAccessTime(int)
          * @see #getLastAccessBackgroundTime(int)
          * @see #getLastAccessTime(int, int, int)
-         * @see OpFeatureEntry#getLastAccessForegroundTime(int)
+         * @see AttributedOpEntry#getLastAccessForegroundTime(int)
          */
         public long getLastAccessForegroundTime(@OpFlags int flags) {
             return getLastAccessTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -3677,7 +3823,7 @@
          * @see #getLastAccessTime(int)
          * @see #getLastAccessForegroundTime(int)
          * @see #getLastAccessTime(int, int, int)
-         * @see OpFeatureEntry#getLastAccessBackgroundTime(int)
+         * @see AttributedOpEntry#getLastAccessBackgroundTime(int)
          */
         public long getLastAccessBackgroundTime(@OpFlags int flags) {
             return getLastAccessTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -3694,13 +3840,14 @@
         private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
                 @UidState int toUidState, @OpFlags int flags) {
             NoteOpEvent lastAccessEvent = null;
-            for (OpFeatureEntry featureEntry : mFeatures.values()) {
-                NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastAccessEvent(fromUidState,
-                        toUidState, flags);
+            for (AttributedOpEntry attributionEntry : mAttributedOpEntries.values()) {
+                NoteOpEvent lastAttributionAccessEvent = attributionEntry.getLastAccessEvent(
+                        fromUidState, toUidState, flags);
 
-                if (lastAccessEvent == null || (lastFeatureAccessEvent != null
-                        && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
-                    lastAccessEvent = lastFeatureAccessEvent;
+                if (lastAccessEvent == null || (lastAttributionAccessEvent != null
+                        && lastAttributionAccessEvent.getNoteTime()
+                        > lastAccessEvent.getNoteTime())) {
+                    lastAccessEvent = lastAttributionAccessEvent;
                 }
             }
 
@@ -3720,7 +3867,7 @@
          * @see #getLastAccessTime(int)
          * @see #getLastAccessForegroundTime(int)
          * @see #getLastAccessBackgroundTime(int)
-         * @see OpFeatureEntry#getLastAccessTime(int, int, int)
+         * @see AttributedOpEntry#getLastAccessTime(int, int, int)
          */
         public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
                 @OpFlags int flags) {
@@ -3756,7 +3903,7 @@
          * @see #getLastRejectForegroundTime(int)
          * @see #getLastRejectBackgroundTime(int)
          * @see #getLastRejectTime(int, int, int)
-         * @see OpFeatureEntry#getLastRejectTime(int)
+         * @see AttributedOpEntry#getLastRejectTime(int)
          */
         public long getLastRejectTime(@OpFlags int flags) {
             return getLastRejectTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3773,7 +3920,7 @@
          * @see #getLastRejectTime(int)
          * @see #getLastRejectBackgroundTime(int)
          * @see #getLastRejectTime(int, int, int)
-         * @see OpFeatureEntry#getLastRejectForegroundTime(int)
+         * @see AttributedOpEntry#getLastRejectForegroundTime(int)
          */
         public long getLastRejectForegroundTime(@OpFlags int flags) {
             return getLastRejectTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -3791,7 +3938,7 @@
          * @see #getLastRejectTime(int)
          * @see #getLastRejectForegroundTime(int)
          * @see #getLastRejectTime(int, int, int)
-         * @see OpFeatureEntry#getLastRejectBackgroundTime(int)
+         * @see AttributedOpEntry#getLastRejectBackgroundTime(int)
          */
         public long getLastRejectBackgroundTime(@OpFlags int flags) {
             return getLastRejectTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -3808,13 +3955,14 @@
         private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
                 @UidState int toUidState, @OpFlags int flags) {
             NoteOpEvent lastAccessEvent = null;
-            for (OpFeatureEntry featureEntry : mFeatures.values()) {
-                NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastRejectEvent(fromUidState,
-                        toUidState, flags);
+            for (AttributedOpEntry attributionEntry : mAttributedOpEntries.values()) {
+                NoteOpEvent lastAttributionAccessEvent = attributionEntry.getLastRejectEvent(
+                        fromUidState, toUidState, flags);
 
-                if (lastAccessEvent == null || (lastFeatureAccessEvent != null
-                        && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
-                    lastAccessEvent = lastFeatureAccessEvent;
+                if (lastAccessEvent == null || (lastAttributionAccessEvent != null
+                        && lastAttributionAccessEvent.getNoteTime()
+                        > lastAccessEvent.getNoteTime())) {
+                    lastAccessEvent = lastAttributionAccessEvent;
                 }
             }
 
@@ -3835,7 +3983,7 @@
          * @see #getLastRejectForegroundTime(int)
          * @see #getLastRejectBackgroundTime(int)
          * @see #getLastRejectTime(int, int, int)
-         * @see OpFeatureEntry#getLastRejectTime(int, int, int)
+         * @see AttributedOpEntry#getLastRejectTime(int, int, int)
          */
         public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
                 @OpFlags int flags) {
@@ -3851,8 +3999,8 @@
          * @return Whether the operation is running.
          */
         public boolean isRunning() {
-            for (OpFeatureEntry opFeatureEntry : mFeatures.values()) {
-                if (opFeatureEntry.isRunning()) {
+            for (AttributedOpEntry opAttributionEntry : mAttributedOpEntries.values()) {
+                if (opAttributionEntry.isRunning()) {
                     return true;
                 }
             }
@@ -3878,7 +4026,7 @@
          * @see #getLastForegroundDuration(int)
          * @see #getLastBackgroundDuration(int)
          * @see #getLastDuration(int, int, int)
-         * @see OpFeatureEntry#getLastDuration(int)
+         * @see AttributedOpEntry#getLastDuration(int)
          */
         public long getLastDuration(@OpFlags int flags) {
             return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3894,7 +4042,7 @@
          * @see #getLastDuration(int)
          * @see #getLastBackgroundDuration(int)
          * @see #getLastDuration(int, int, int)
-         * @see OpFeatureEntry#getLastForegroundDuration(int)
+         * @see AttributedOpEntry#getLastForegroundDuration(int)
          */
         public long getLastForegroundDuration(@OpFlags int flags) {
             return getLastDuration(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -3911,7 +4059,7 @@
          * @see #getLastDuration(int)
          * @see #getLastForegroundDuration(int)
          * @see #getLastDuration(int, int, int)
-         * @see OpFeatureEntry#getLastBackgroundDuration(int)
+         * @see AttributedOpEntry#getLastBackgroundDuration(int)
          */
         public long getLastBackgroundDuration(@OpFlags int flags) {
             return getLastDuration(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -3930,7 +4078,7 @@
          * @see #getLastDuration(int)
          * @see #getLastForegroundDuration(int)
          * @see #getLastBackgroundDuration(int)
-         * @see OpFeatureEntry#getLastDuration(int, int, int)
+         * @see AttributedOpEntry#getLastDuration(int, int, int)
          */
         public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
                 @OpFlags int flags) {
@@ -4005,7 +4153,7 @@
          * @see #getLastForegroundProxyInfo(int)
          * @see #getLastBackgroundProxyInfo(int)
          * @see #getLastProxyInfo(int, int, int)
-         * @see OpFeatureEntry#getLastProxyInfo(int)
+         * @see AttributedOpEntry#getLastProxyInfo(int)
          */
         public @Nullable OpEventProxyInfo getLastProxyInfo(@OpFlags int flags) {
             return getLastProxyInfo(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -4022,7 +4170,7 @@
          * @see #getLastProxyInfo(int)
          * @see #getLastBackgroundProxyInfo(int)
          * @see #getLastProxyInfo(int, int, int)
-         * @see OpFeatureEntry#getLastForegroundProxyInfo(int)
+         * @see AttributedOpEntry#getLastForegroundProxyInfo(int)
          */
         public @Nullable OpEventProxyInfo getLastForegroundProxyInfo(@OpFlags int flags) {
             return getLastProxyInfo(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -4040,7 +4188,7 @@
          * @see #getLastProxyInfo(int)
          * @see #getLastForegroundProxyInfo(int)
          * @see #getLastProxyInfo(int, int, int)
-         * @see OpFeatureEntry#getLastBackgroundProxyInfo(int)
+         * @see AttributedOpEntry#getLastBackgroundProxyInfo(int)
          */
         public @Nullable OpEventProxyInfo getLastBackgroundProxyInfo(@OpFlags int flags) {
             return getLastProxyInfo(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -4060,7 +4208,7 @@
          * @see #getLastProxyInfo(int)
          * @see #getLastForegroundProxyInfo(int)
          * @see #getLastBackgroundProxyInfo(int)
-         * @see OpFeatureEntry#getLastProxyInfo(int, int, int)
+         * @see AttributedOpEntry#getLastProxyInfo(int, int, int)
          */
         public @Nullable OpEventProxyInfo getLastProxyInfo(@UidState int fromUidState,
                 @UidState int toUidState, @OpFlags int flags) {
@@ -4094,15 +4242,15 @@
          *   The code of the op
          * @param mode
          *   The mode of the op
-         * @param features
-         *   The features that have been used when checking the op
+         * @param attributedOpEntries
+         *   The attributions that have been used when noting the op
          * @hide
          */
         @DataClass.Generated.Member
         public OpEntry(
                 @IntRange(from = 0, to = _NUM_OP - 1) int op,
                 @Mode int mode,
-                @NonNull Map<String,OpFeatureEntry> features) {
+                @NonNull Map<String, AttributedOpEntry> attributedOpEntries) {
             this.mOp = op;
             com.android.internal.util.AnnotationValidations.validate(
                     IntRange.class, null, mOp,
@@ -4111,9 +4259,9 @@
             this.mMode = mode;
             com.android.internal.util.AnnotationValidations.validate(
                     Mode.class, null, mMode);
-            this.mFeatures = features;
+            this.mAttributedOpEntries = attributedOpEntries;
             com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mFeatures);
+                    NonNull.class, null, mAttributedOpEntries);
 
             // onConstructed(); // You can define this method to get a callback
         }
@@ -4127,14 +4275,14 @@
         }
 
         /**
-         * The features that have been used when checking the op keyed by id of the feature.
+         * The attributed entries keyed by attribution tag.
          *
-         * @see Context#createFeatureContext(String)
+         * @see Context#createAttributionContext(String)
          * @see #noteOp(String, int, String, String, String)
          */
         @DataClass.Generated.Member
-        public @NonNull Map<String,OpFeatureEntry> getFeatures() {
-            return mFeatures;
+        public @NonNull Map<String, AttributedOpEntry> getAttributedOpEntries() {
+            return mAttributedOpEntries;
         }
 
         @Override
@@ -4145,7 +4293,7 @@
 
             dest.writeInt(mOp);
             dest.writeInt(mMode);
-            dest.writeMap(mFeatures);
+            dest.writeMap(mAttributedOpEntries);
         }
 
         @Override
@@ -4161,8 +4309,8 @@
 
             int op = in.readInt();
             int mode = in.readInt();
-            Map<String,OpFeatureEntry> features = new java.util.LinkedHashMap<>();
-            in.readMap(features, OpFeatureEntry.class.getClassLoader());
+            Map<String, AttributedOpEntry> attributions = new java.util.LinkedHashMap<>();
+            in.readMap(attributions, AttributedOpEntry.class.getClassLoader());
 
             this.mOp = op;
             com.android.internal.util.AnnotationValidations.validate(
@@ -4172,9 +4320,9 @@
             this.mMode = mode;
             com.android.internal.util.AnnotationValidations.validate(
                     Mode.class, null, mMode);
-            this.mFeatures = features;
+            this.mAttributedOpEntries = attributions;
             com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mFeatures);
+                    NonNull.class, null, mAttributedOpEntries);
 
             // onConstructed(); // You can define this method to get a callback
         }
@@ -4198,7 +4346,7 @@
                 time = 1574809856259L,
                 codegenVersion = "1.0.14",
                 sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
-                inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final @android.app.Mode int mMode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.app.OpFeatureEntry> mFeatures\npublic @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getOpStr()}\") int getOp()\npublic @android.annotation.NonNull java.lang.String getOpStr()\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getAccessTime(int, int)}\") long getTime()\npublic @java.lang.Deprecated long getLastAccessTime(int)\npublic @java.lang.Deprecated long getLastAccessForegroundTime(int)\npublic @java.lang.Deprecated long getLastAccessBackgroundTime(int)\npublic @java.lang.Deprecated long getLastAccessTime(int,int,int)\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getLastRejectTime(int, int, int)}\") long getRejectTime()\npublic @java.lang.Deprecated long getLastRejectTime(int)\npublic @java.lang.Deprecated long getLastRejectForegroundTime(int)\npublic @java.lang.Deprecated long getLastRejectBackgroundTime(int)\npublic @java.lang.Deprecated long getLastRejectTime(int,int,int)\npublic  long getAccessTime(int,int)\npublic  long getRejectTime(int,int)\npublic  boolean isRunning()\nprivate  android.app.NoteOpEvent getLastAccessEvent(int,int,int)\npublic @java.lang.Deprecated long getDuration()\npublic @java.lang.Deprecated long getLastForegroundDuration(int)\npublic @java.lang.Deprecated long getLastBackgroundDuration(int)\npublic @java.lang.Deprecated long getLastDuration(int,int,int)\npublic @java.lang.Deprecated int getProxyUid()\npublic @java.lang.Deprecated @android.annotation.Nullable java.lang.String getProxyPackageName()\nprivate @android.app.UidState int getLastAccessUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\nprivate @android.app.UidState int getLastRejectUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic  long getDuration(int,int)\npublic  int getProxyUid(int,int)\nprivate  int getProxyUid(int,int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\nprivate @android.annotation.Nullable java.lang.String getProxyPackageName(int,int,int)\nclass OpEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+                inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final @android.app.Mode int mMode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.app.OpAttributionEntry> mAttributions\npublic @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getOpStr()}\") int getOp()\npublic @android.annotation.NonNull java.lang.String getOpStr()\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getAccessTime(int, int)}\") long getTime()\npublic @java.lang.Deprecated long getLastAccessTime(int)\npublic @java.lang.Deprecated long getLastAccessForegroundTime(int)\npublic @java.lang.Deprecated long getLastAccessBackgroundTime(int)\npublic @java.lang.Deprecated long getLastAccessTime(int,int,int)\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getLastRejectTime(int, int, int)}\") long getRejectTime()\npublic @java.lang.Deprecated long getLastRejectTime(int)\npublic @java.lang.Deprecated long getLastRejectForegroundTime(int)\npublic @java.lang.Deprecated long getLastRejectBackgroundTime(int)\npublic @java.lang.Deprecated long getLastRejectTime(int,int,int)\npublic  long getAccessTime(int,int)\npublic  long getRejectTime(int,int)\npublic  boolean isRunning()\nprivate  android.app.NoteOpEvent getLastAccessEvent(int,int,int)\npublic @java.lang.Deprecated long getDuration()\npublic @java.lang.Deprecated long getLastForegroundDuration(int)\npublic @java.lang.Deprecated long getLastBackgroundDuration(int)\npublic @java.lang.Deprecated long getLastDuration(int,int,int)\npublic @java.lang.Deprecated int getProxyUid()\npublic @java.lang.Deprecated @android.annotation.Nullable java.lang.String getProxyPackageName()\nprivate @android.app.UidState int getLastAccessUidStateForFlagsInStatesOfAllAttributions(int,int,int)\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\nprivate @android.app.UidState int getLastRejectUidStateForFlagsInStatesOfAllAttributions(int,int,int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic  long getDuration(int,int)\npublic  int getProxyUid(int,int)\nprivate  int getProxyUid(int,int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\nprivate @android.annotation.Nullable java.lang.String getProxyPackageName(int,int,int)\nclass OpEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
         @Deprecated
         private void __metadata() {}
          */
@@ -4214,7 +4362,7 @@
         void visitHistoricalOps(@NonNull HistoricalOps ops);
         void visitHistoricalUidOps(@NonNull HistoricalUidOps ops);
         void visitHistoricalPackageOps(@NonNull HistoricalPackageOps ops);
-        void visitHistoricalFeatureOps(@NonNull HistoricalFeatureOps ops);
+        void visitHistoricalAttributionOps(@NonNull AttributedHistoricalOps ops);
         void visitHistoricalOp(@NonNull HistoricalOp ops);
     }
 
@@ -4227,7 +4375,7 @@
     @IntDef(flag = true, prefix = { "FILTER_BY_" }, value = {
             FILTER_BY_UID,
             FILTER_BY_PACKAGE_NAME,
-            FILTER_BY_FEATURE_ID,
+            FILTER_BY_ATTRIBUTION_TAG,
             FILTER_BY_OP_NAMES
     })
     public @interface HistoricalOpsRequestFilter {}
@@ -4247,11 +4395,11 @@
     public static final int FILTER_BY_PACKAGE_NAME = 1<<1;
 
     /**
-     * Filter historical appop request by feature id.
+     * Filter historical appop request by attribution tag.
      *
      * @hide
      */
-    public static final int FILTER_BY_FEATURE_ID = 1<<2;
+    public static final int FILTER_BY_ATTRIBUTION_TAG = 1<<2;
 
     /**
      * Filter historical appop request by op names.
@@ -4272,7 +4420,7 @@
     public static final class HistoricalOpsRequest {
         private final int mUid;
         private final @Nullable String mPackageName;
-        private final @Nullable String mFeatureId;
+        private final @Nullable String mAttributionTag;
         private final @Nullable List<String> mOpNames;
         private final @HistoricalOpsRequestFilter int mFilter;
         private final long mBeginTimeMillis;
@@ -4280,12 +4428,12 @@
         private final @OpFlags int mFlags;
 
         private HistoricalOpsRequest(int uid, @Nullable String packageName,
-                @Nullable String featureId, @Nullable List<String> opNames,
+                @Nullable String attributionTag, @Nullable List<String> opNames,
                 @HistoricalOpsRequestFilter int filter, long beginTimeMillis,
                 long endTimeMillis, @OpFlags int flags) {
             mUid = uid;
             mPackageName = packageName;
-            mFeatureId = featureId;
+            mAttributionTag = attributionTag;
             mOpNames = opNames;
             mFilter = filter;
             mBeginTimeMillis = beginTimeMillis;
@@ -4303,7 +4451,7 @@
         public static final class Builder {
             private int mUid = Process.INVALID_UID;
             private @Nullable String mPackageName;
-            private @Nullable String mFeatureId;
+            private @Nullable String mAttributionTag;
             private @Nullable List<String> mOpNames;
             private @HistoricalOpsRequestFilter int mFilter;
             private final long mBeginTimeMillis;
@@ -4367,14 +4515,14 @@
             }
 
             /**
-             * Sets the feature id to query for.
+             * Sets the attribution tag to query for.
              *
-             * @param featureId The id of the feature.
+             * @param attributionTag attribution tag
              * @return This builder.
              */
-            public @NonNull Builder setFeatureId(@Nullable String featureId) {
-                mFeatureId = featureId;
-                mFilter |= FILTER_BY_FEATURE_ID;
+            public @NonNull Builder setAttributionTag(@Nullable String attributionTag) {
+                mAttributionTag = attributionTag;
+                mFilter |= FILTER_BY_ATTRIBUTION_TAG;
 
                 return this;
             }
@@ -4425,7 +4573,7 @@
              * @return a new {@link HistoricalOpsRequest}.
              */
             public @NonNull HistoricalOpsRequest build() {
-                return new HistoricalOpsRequest(mUid, mPackageName, mFeatureId, mOpNames,
+                return new HistoricalOpsRequest(mUid, mPackageName, mAttributionTag, mOpNames,
                         mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
             }
         }
@@ -4585,7 +4733,7 @@
          *
          * @param uid Uid to filter for.
          * @param packageName Package to filter for.
-         * @param featureId Package to filter for.
+         * @param attributionTag attribution tag to filter for
          * @param opNames Ops to filter for.
          * @param filter Which parameters to filter on.
          * @param beginTimeMillis The begin time to filter for or {@link Long#MIN_VALUE} for all.
@@ -4593,7 +4741,7 @@
          *
          * @hide
          */
-        public void filter(int uid, @Nullable String packageName, @Nullable String featureId,
+        public void filter(int uid, @Nullable String packageName, @Nullable String attributionTag,
                 @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
                 long beginTimeMillis, long endTimeMillis) {
             final long durationMillis = getDurationMillis();
@@ -4607,7 +4755,7 @@
                 if ((filter & FILTER_BY_UID) != 0 && uid != uidOp.getUid()) {
                     mHistoricalUidOps.removeAt(i);
                 } else {
-                    uidOp.filter(packageName, featureId, opNames, filter, scaleFactor);
+                    uidOp.filter(packageName, attributionTag, opNames, filter, scaleFactor);
                     if (uidOp.getPackageCount() == 0) {
                         mHistoricalUidOps.removeAt(i);
                     }
@@ -4638,28 +4786,28 @@
         /** @hide */
         @TestApi
         public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
-                @Nullable String featureId, @UidState int uidState,  @OpFlags int flags,
+                @Nullable String attributionTag, @UidState int uidState,  @OpFlags int flags,
                 long increment) {
             getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
-                    packageName, featureId, uidState, flags, increment);
+                    packageName, attributionTag, uidState, flags, increment);
         }
 
         /** @hide */
         @TestApi
         public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
-                @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+                @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
                 long increment) {
             getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
-                    packageName, featureId, uidState, flags, increment);
+                    packageName, attributionTag, uidState, flags, increment);
         }
 
         /** @hide */
         @TestApi
         public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
-                @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+                @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
                 long increment) {
             getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
-                    packageName, featureId, uidState, flags, increment);
+                    packageName, attributionTag, uidState, flags, increment);
         }
 
         /** @hide */
@@ -4939,7 +5087,7 @@
             }
         }
 
-        private void filter(@Nullable String packageName, @Nullable String featureId,
+        private void filter(@Nullable String packageName, @Nullable String attributionTag,
                 @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
                 double fractionToRemove) {
             final int packageCount = getPackageCount();
@@ -4949,8 +5097,8 @@
                         packageOps.getPackageName())) {
                     mHistoricalPackageOps.removeAt(i);
                 } else {
-                    packageOps.filter(featureId, opNames, filter, fractionToRemove);
-                    if (packageOps.getFeatureCount() == 0) {
+                    packageOps.filter(attributionTag, opNames, filter, fractionToRemove);
+                    if (packageOps.getAttributedOpsCount() == 0) {
                         mHistoricalPackageOps.removeAt(i);
                     }
                 }
@@ -4969,24 +5117,24 @@
         }
 
         private void increaseAccessCount(int opCode, @NonNull String packageName,
-                @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+                @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
                 long increment) {
             getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
-                    opCode, featureId, uidState, flags, increment);
+                    opCode, attributionTag, uidState, flags, increment);
         }
 
         private void increaseRejectCount(int opCode, @NonNull String packageName,
-                @Nullable String featureId, @UidState int uidState,  @OpFlags int flags,
+                @Nullable String attributionTag, @UidState int uidState,  @OpFlags int flags,
                 long increment) {
             getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
-                    opCode, featureId, uidState, flags, increment);
+                    opCode, attributionTag, uidState, flags, increment);
         }
 
         private void increaseAccessDuration(int opCode, @NonNull String packageName,
-                @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+                @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
                 long increment) {
             getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
-                    opCode, featureId, uidState, flags, increment);
+                    opCode, attributionTag, uidState, flags, increment);
         }
 
         /**
@@ -5131,7 +5279,7 @@
     @SystemApi
     public static final class HistoricalPackageOps implements Parcelable {
         private final @NonNull String mPackageName;
-        private @Nullable ArrayMap<String, HistoricalFeatureOps> mHistoricalFeatureOps;
+        private @Nullable ArrayMap<String, AttributedHistoricalOps> mAttributedHistoricalOps;
 
         /** @hide */
         public HistoricalPackageOps(@NonNull String packageName) {
@@ -5140,70 +5288,71 @@
 
         private HistoricalPackageOps(@NonNull HistoricalPackageOps other) {
             mPackageName = other.mPackageName;
-            final int opCount = other.getFeatureCount();
+            final int opCount = other.getAttributedOpsCount();
             for (int i = 0; i < opCount; i++) {
-                final HistoricalFeatureOps origOps = other.getFeatureOpsAt(i);
-                final HistoricalFeatureOps cloneOps = new HistoricalFeatureOps(origOps);
-                if (mHistoricalFeatureOps == null) {
-                    mHistoricalFeatureOps = new ArrayMap<>(opCount);
+                final AttributedHistoricalOps origOps = other.getAttributedOpsAt(i);
+                final AttributedHistoricalOps cloneOps = new AttributedHistoricalOps(origOps);
+                if (mAttributedHistoricalOps == null) {
+                    mAttributedHistoricalOps = new ArrayMap<>(opCount);
                 }
-                mHistoricalFeatureOps.put(cloneOps.getFeatureId(), cloneOps);
+                mAttributedHistoricalOps.put(cloneOps.getTag(), cloneOps);
             }
         }
 
         private HistoricalPackageOps(@NonNull Parcel parcel) {
             mPackageName = parcel.readString();
-            mHistoricalFeatureOps = parcel.createTypedArrayMap(HistoricalFeatureOps.CREATOR);
+            mAttributedHistoricalOps = parcel.createTypedArrayMap(AttributedHistoricalOps.CREATOR);
         }
 
         private @Nullable HistoricalPackageOps splice(double fractionToRemove) {
             HistoricalPackageOps splice = null;
-            final int featureCount = getFeatureCount();
-            for (int i = 0; i < featureCount; i++) {
-                final HistoricalFeatureOps origOps = getFeatureOpsAt(i);
-                final HistoricalFeatureOps spliceOps = origOps.splice(fractionToRemove);
+            final int attributionCount = getAttributedOpsCount();
+            for (int i = 0; i < attributionCount; i++) {
+                final AttributedHistoricalOps origOps = getAttributedOpsAt(i);
+                final AttributedHistoricalOps spliceOps = origOps.splice(fractionToRemove);
                 if (spliceOps != null) {
                     if (splice == null) {
                         splice = new HistoricalPackageOps(mPackageName);
                     }
-                    if (splice.mHistoricalFeatureOps == null) {
-                        splice.mHistoricalFeatureOps = new ArrayMap<>();
+                    if (splice.mAttributedHistoricalOps == null) {
+                        splice.mAttributedHistoricalOps = new ArrayMap<>();
                     }
-                    splice.mHistoricalFeatureOps.put(spliceOps.getFeatureId(), spliceOps);
+                    splice.mAttributedHistoricalOps.put(spliceOps.getTag(), spliceOps);
                 }
             }
             return splice;
         }
 
         private void merge(@NonNull HistoricalPackageOps other) {
-            final int featureCount = other.getFeatureCount();
-            for (int i = 0; i < featureCount; i++) {
-                final HistoricalFeatureOps otherFeatureOps = other.getFeatureOpsAt(i);
-                final HistoricalFeatureOps thisFeatureOps = getFeatureOps(
-                        otherFeatureOps.getFeatureId());
-                if (thisFeatureOps != null) {
-                    thisFeatureOps.merge(otherFeatureOps);
+            final int attributionCount = other.getAttributedOpsCount();
+            for (int i = 0; i < attributionCount; i++) {
+                final AttributedHistoricalOps otherAttributionOps = other.getAttributedOpsAt(i);
+                final AttributedHistoricalOps thisAttributionOps = getAttributedOps(
+                        otherAttributionOps.getTag());
+                if (thisAttributionOps != null) {
+                    thisAttributionOps.merge(otherAttributionOps);
                 } else {
-                    if (mHistoricalFeatureOps == null) {
-                        mHistoricalFeatureOps = new ArrayMap<>();
+                    if (mAttributedHistoricalOps == null) {
+                        mAttributedHistoricalOps = new ArrayMap<>();
                     }
-                    mHistoricalFeatureOps.put(otherFeatureOps.getFeatureId(), otherFeatureOps);
+                    mAttributedHistoricalOps.put(otherAttributionOps.getTag(),
+                            otherAttributionOps);
                 }
             }
         }
 
-        private void filter(@Nullable String featureId, @Nullable String[] opNames,
+        private void filter(@Nullable String attributionTag, @Nullable String[] opNames,
                 @HistoricalOpsRequestFilter int filter, double fractionToRemove) {
-            final int featureCount = getFeatureCount();
-            for (int i = featureCount - 1; i >= 0; i--) {
-                final HistoricalFeatureOps featureOps = getFeatureOpsAt(i);
-                if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(featureId,
-                        featureOps.getFeatureId())) {
-                    mHistoricalFeatureOps.removeAt(i);
+            final int attributionCount = getAttributedOpsCount();
+            for (int i = attributionCount - 1; i >= 0; i--) {
+                final AttributedHistoricalOps attributionOps = getAttributedOpsAt(i);
+                if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(attributionTag,
+                        attributionOps.getTag())) {
+                    mAttributedHistoricalOps.removeAt(i);
                 } else {
-                    featureOps.filter(opNames, filter, fractionToRemove);
-                    if (featureOps.getOpCount() == 0) {
-                        mHistoricalFeatureOps.removeAt(i);
+                    attributionOps.filter(opNames, filter, fractionToRemove);
+                    if (attributionOps.getOpCount() == 0) {
+                        mAttributedHistoricalOps.removeAt(i);
                     }
                 }
             }
@@ -5211,38 +5360,38 @@
 
         private void accept(@NonNull HistoricalOpsVisitor visitor) {
             visitor.visitHistoricalPackageOps(this);
-            final int featureCount = getFeatureCount();
-            for (int i = 0; i < featureCount; i++) {
-                getFeatureOpsAt(i).accept(visitor);
+            final int attributionCount = getAttributedOpsCount();
+            for (int i = 0; i < attributionCount; i++) {
+                getAttributedOpsAt(i).accept(visitor);
             }
         }
 
         private boolean isEmpty() {
-            final int featureCount = getFeatureCount();
-            for (int i = featureCount - 1; i >= 0; i--) {
-                final HistoricalFeatureOps featureOps = mHistoricalFeatureOps.valueAt(i);
-                if (!featureOps.isEmpty()) {
+            final int attributionCount = getAttributedOpsCount();
+            for (int i = attributionCount - 1; i >= 0; i--) {
+                final AttributedHistoricalOps attributionOps = mAttributedHistoricalOps.valueAt(i);
+                if (!attributionOps.isEmpty()) {
                     return false;
                 }
             }
             return true;
         }
 
-        private void increaseAccessCount(int opCode, @Nullable String featureId,
+        private void increaseAccessCount(int opCode, @Nullable String attributionTag,
                 @UidState int uidState, @OpFlags int flags, long increment) {
-            getOrCreateHistoricalFeatureOps(featureId).increaseAccessCount(
+            getOrCreateAttributedHistoricalOps(attributionTag).increaseAccessCount(
                     opCode, uidState, flags, increment);
         }
 
-        private void increaseRejectCount(int opCode, @Nullable String featureId,
+        private void increaseRejectCount(int opCode, @Nullable String attributionTag,
                 @UidState int uidState, @OpFlags int flags, long increment) {
-            getOrCreateHistoricalFeatureOps(featureId).increaseRejectCount(
+            getOrCreateAttributedHistoricalOps(attributionTag).increaseRejectCount(
                     opCode, uidState, flags, increment);
         }
 
-        private void increaseAccessDuration(int opCode, @Nullable String featureId,
+        private void increaseAccessDuration(int opCode, @Nullable String attributionTag,
                 @UidState int uidState, @OpFlags int flags, long increment) {
-            getOrCreateHistoricalFeatureOps(featureId).increaseAccessDuration(
+            getOrCreateAttributedHistoricalOps(attributionTag).increaseAccessDuration(
                     opCode, uidState, flags, increment);
         }
 
@@ -5255,17 +5404,18 @@
             return mPackageName;
         }
 
-        private @NonNull HistoricalFeatureOps getOrCreateHistoricalFeatureOps(
-                @Nullable String featureId) {
-            if (mHistoricalFeatureOps == null) {
-                mHistoricalFeatureOps = new ArrayMap<>();
+        private @NonNull AttributedHistoricalOps getOrCreateAttributedHistoricalOps(
+                @Nullable String attributionTag) {
+            if (mAttributedHistoricalOps == null) {
+                mAttributedHistoricalOps = new ArrayMap<>();
             }
-            HistoricalFeatureOps historicalFeatureOp = mHistoricalFeatureOps.get(featureId);
-            if (historicalFeatureOp == null) {
-                historicalFeatureOp = new HistoricalFeatureOps(featureId);
-                mHistoricalFeatureOps.put(featureId, historicalFeatureOp);
+            AttributedHistoricalOps historicalAttributionOp = mAttributedHistoricalOps.get(
+                    attributionTag);
+            if (historicalAttributionOp == null) {
+                historicalAttributionOp = new AttributedHistoricalOps(attributionTag);
+                mAttributedHistoricalOps.put(attributionTag, historicalAttributionOp);
             }
-            return historicalFeatureOp;
+            return historicalAttributionOp;
         }
 
         /**
@@ -5276,13 +5426,13 @@
          */
         public @IntRange(from = 0) int getOpCount() {
             int numOps = 0;
-            int numFeatures = getFeatureCount();
+            int numAttributions = getAttributedOpsCount();
 
             for (int code = 0; code < _NUM_OP; code++) {
                 String opName = opToPublicName(code);
 
-                for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                    if (getFeatureOpsAt(featureNum).getOp(opName) != null) {
+                for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+                    if (getAttributedOpsAt(attributionNum).getOp(opName) != null) {
                         numOps++;
                         break;
                     }
@@ -5295,7 +5445,7 @@
         /**
          * Gets the historical op at a given index.
          *
-         * <p>This combines the counts from all features.
+         * <p>This combines the counts from all attributions.
          *
          * @param index The index to lookup.
          * @return The op at the given index.
@@ -5303,13 +5453,13 @@
          */
         public @NonNull HistoricalOp getOpAt(@IntRange(from = 0) int index) {
             int numOpsFound = 0;
-            int numFeatures = getFeatureCount();
+            int numAttributions = getAttributedOpsCount();
 
             for (int code = 0; code < _NUM_OP; code++) {
                 String opName = opToPublicName(code);
 
-                for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                    if (getFeatureOpsAt(featureNum).getOp(opName) != null) {
+                for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+                    if (getAttributedOpsAt(attributionNum).getOp(opName) != null) {
                         if (numOpsFound == index) {
                             return getOp(opName);
                         } else {
@@ -5326,25 +5476,25 @@
         /**
          * Gets the historical entry for a given op name.
          *
-         * <p>This combines the counts from all features.
+         * <p>This combines the counts from all attributions.
          *
          * @param opName The op name.
          * @return The historical entry for that op name.
          */
         public @Nullable HistoricalOp getOp(@NonNull String opName) {
-            if (mHistoricalFeatureOps == null) {
+            if (mAttributedHistoricalOps == null) {
                 return null;
             }
 
             HistoricalOp combinedOp = null;
-            int numFeatures = getFeatureCount();
-            for (int i = 0; i < numFeatures; i++) {
-                HistoricalOp featureOp = getFeatureOpsAt(i).getOp(opName);
-                if (featureOp != null) {
+            int numAttributions = getAttributedOpsCount();
+            for (int i = 0; i < numAttributions; i++) {
+                HistoricalOp attributionOp = getAttributedOpsAt(i).getOp(opName);
+                if (attributionOp != null) {
                     if (combinedOp == null) {
-                        combinedOp = new HistoricalOp(featureOp);
+                        combinedOp = new HistoricalOp(attributionOp);
                     } else {
-                        combinedOp.merge(featureOp);
+                        combinedOp.merge(attributionOp);
                     }
                 }
             }
@@ -5360,7 +5510,7 @@
         @Override
         public void writeToParcel(@NonNull Parcel parcel, int flags) {
             parcel.writeString(mPackageName);
-            parcel.writeTypedArrayMap(mHistoricalFeatureOps, flags);
+            parcel.writeTypedArrayMap(mAttributedHistoricalOps, flags);
         }
 
         public static final @android.annotation.NonNull Creator<HistoricalPackageOps> CREATOR =
@@ -5388,11 +5538,11 @@
             if (!mPackageName.equals(other.mPackageName)) {
                 return false;
             }
-            if (mHistoricalFeatureOps == null) {
-                if (other.mHistoricalFeatureOps != null) {
+            if (mAttributedHistoricalOps == null) {
+                if (other.mAttributedHistoricalOps != null) {
                     return false;
                 }
-            } else if (!mHistoricalFeatureOps.equals(other.mHistoricalFeatureOps)) {
+            } else if (!mAttributedHistoricalOps.equals(other.mAttributedHistoricalOps)) {
                 return false;
             }
             return true;
@@ -5401,58 +5551,58 @@
         @Override
         public int hashCode() {
             int result = mPackageName != null ? mPackageName.hashCode() : 0;
-            result = 31 * result + (mHistoricalFeatureOps != null ? mHistoricalFeatureOps.hashCode()
-                    : 0);
+            result = 31 * result + (mAttributedHistoricalOps != null
+                    ? mAttributedHistoricalOps.hashCode() : 0);
             return result;
         }
 
         /**
-         * Gets number of feature with historical ops.
+         * Gets number of attributed historical ops.
          *
-         * @return The number of feature with historical ops.
+         * @return The number of attribution with historical ops.
          *
-         * @see #getFeatureOpsAt(int)
+         * @see #getAttributedOpsAt(int)
          */
-        public @IntRange(from = 0) int getFeatureCount() {
-            if (mHistoricalFeatureOps == null) {
+        public @IntRange(from = 0) int getAttributedOpsCount() {
+            if (mAttributedHistoricalOps == null) {
                 return 0;
             }
-            return mHistoricalFeatureOps.size();
+            return mAttributedHistoricalOps.size();
         }
 
         /**
-         * Gets the historical feature ops at a given index.
+         * Gets the attributed historical ops at a given index.
          *
          * @param index The index.
          *
-         * @return The historical feature ops at the given index.
+         * @return The historical attribution ops at the given index.
          *
-         * @see #getFeatureCount()
+         * @see #getAttributedOpsCount()
          */
-        public @NonNull HistoricalFeatureOps getFeatureOpsAt(@IntRange(from = 0) int index) {
-            if (mHistoricalFeatureOps == null) {
+        public @NonNull AttributedHistoricalOps getAttributedOpsAt(@IntRange(from = 0) int index) {
+            if (mAttributedHistoricalOps == null) {
                 throw new IndexOutOfBoundsException();
             }
-            return mHistoricalFeatureOps.valueAt(index);
+            return mAttributedHistoricalOps.valueAt(index);
         }
 
         /**
-         * Gets the historical feature ops for a given feature.
+         * Gets the attributed historical ops for a given attribution tag.
          *
-         * @param featureId The feature id.
+         * @param attributionTag The attribution tag.
          *
-         * @return The historical ops for the feature.
+         * @return The historical ops for the attribution.
          */
-        public @Nullable HistoricalFeatureOps getFeatureOps(@NonNull String featureId) {
-            if (mHistoricalFeatureOps == null) {
+        public @Nullable AttributedHistoricalOps getAttributedOps(@NonNull String attributionTag) {
+            if (mAttributedHistoricalOps == null) {
                 return null;
             }
-            return mHistoricalFeatureOps.get(featureId);
+            return mAttributedHistoricalOps.get(attributionTag);
         }
     }
 
     /**
-     * This class represents historical app op information about a feature in a package.
+     * This class represents historical app op information about a attribution in a package.
      *
      * @hide
      */
@@ -5462,20 +5612,20 @@
     @DataClass(genHiddenConstructor = true,
             genEqualsHashCode = true, genHiddenCopyConstructor = true) */
     @DataClass.Suppress("getHistoricalOps")
-    public static final class HistoricalFeatureOps implements Parcelable {
-        /** Id of the {@link Context#createFeatureContext feature} in the package */
-        private final @Nullable String mFeatureId;
+    public static final class AttributedHistoricalOps implements Parcelable {
+        /** {@link Context#createAttributionContext attribution} tag */
+        private final @Nullable String mTag;
 
-        /** Ops for this feature */
+        /** Ops for this attribution */
         private @Nullable ArrayMap<String, HistoricalOp> mHistoricalOps;
 
         /** @hide */
-        public HistoricalFeatureOps(@NonNull String featureId) {
-            mFeatureId = featureId;
+        public AttributedHistoricalOps(@NonNull String tag) {
+            mTag = tag;
         }
 
-        private HistoricalFeatureOps(@NonNull HistoricalFeatureOps other) {
-            mFeatureId = other.mFeatureId;
+        private AttributedHistoricalOps(@NonNull AttributedHistoricalOps other) {
+            mTag = other.mTag;
             final int opCount = other.getOpCount();
             for (int i = 0; i < opCount; i++) {
                 final HistoricalOp origOp = other.getOpAt(i);
@@ -5487,15 +5637,15 @@
             }
         }
 
-        private @Nullable HistoricalFeatureOps splice(double fractionToRemove) {
-            HistoricalFeatureOps splice = null;
+        private @Nullable AttributedHistoricalOps splice(double fractionToRemove) {
+            AttributedHistoricalOps splice = null;
             final int opCount = getOpCount();
             for (int i = 0; i < opCount; i++) {
                 final HistoricalOp origOps = getOpAt(i);
                 final HistoricalOp spliceOps = origOps.splice(fractionToRemove);
                 if (spliceOps != null) {
                     if (splice == null) {
-                        splice = new HistoricalFeatureOps(mFeatureId, null);
+                        splice = new AttributedHistoricalOps(mTag, null);
                     }
                     if (splice.mHistoricalOps == null) {
                         splice.mHistoricalOps = new ArrayMap<>();
@@ -5506,7 +5656,7 @@
             return splice;
         }
 
-        private void merge(@NonNull HistoricalFeatureOps other) {
+        private void merge(@NonNull AttributedHistoricalOps other) {
             final int opCount = other.getOpCount();
             for (int i = 0; i < opCount; i++) {
                 final HistoricalOp otherOp = other.getOpAt(i);
@@ -5603,7 +5753,7 @@
         }
 
         private void accept(@NonNull HistoricalOpsVisitor visitor) {
-            visitor.visitHistoricalFeatureOps(this);
+            visitor.visitHistoricalAttributionOps(this);
             final int opCount = getOpCount();
             for (int i = 0; i < opCount; i++) {
                 getOpAt(i).accept(visitor);
@@ -5639,46 +5789,46 @@
 
 
         /**
-         * Creates a new HistoricalFeatureOps.
+         * Creates a new HistoricalAttributionOps.
          *
-         * @param featureId
-         *   Id of the {@link Context#createFeatureContext feature} in the package
+         * @param tag
+         *   {@link Context#createAttributionContext attribution} tag
          * @param historicalOps
-         *   Ops for this feature
+         *   Ops for this attribution
          * @hide
          */
         @DataClass.Generated.Member
-        public HistoricalFeatureOps(
-                @Nullable String featureId,
+        public AttributedHistoricalOps(
+                @Nullable String tag,
                 @Nullable ArrayMap<String,HistoricalOp> historicalOps) {
-            this.mFeatureId = featureId;
+            this.mTag = tag;
             this.mHistoricalOps = historicalOps;
 
             // onConstructed(); // You can define this method to get a callback
         }
 
         /**
-         * Id of the {@link Context#createFeatureContext feature} in the package
+         * {@link Context#createAttributionContext attribution} tag
          */
         @DataClass.Generated.Member
-        public @Nullable String getFeatureId() {
-            return mFeatureId;
+        public @Nullable String getTag() {
+            return mTag;
         }
 
         @Override
         @DataClass.Generated.Member
         public boolean equals(@Nullable Object o) {
             // You can override field equality logic by defining either of the methods like:
-            // boolean fieldNameEquals(HistoricalFeatureOps other) { ... }
+            // boolean fieldNameEquals(HistoricalAttributionOps other) { ... }
             // boolean fieldNameEquals(FieldType otherValue) { ... }
 
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             @SuppressWarnings("unchecked")
-            HistoricalFeatureOps that = (HistoricalFeatureOps) o;
+            AttributedHistoricalOps that = (AttributedHistoricalOps) o;
             //noinspection PointlessBooleanExpression
             return true
-                    && Objects.equals(mFeatureId, that.mFeatureId)
+                    && Objects.equals(mTag, that.mTag)
                     && Objects.equals(mHistoricalOps, that.mHistoricalOps);
         }
 
@@ -5689,7 +5839,7 @@
             // int fieldNameHashCode() { ... }
 
             int _hash = 1;
-            _hash = 31 * _hash + Objects.hashCode(mFeatureId);
+            _hash = 31 * _hash + Objects.hashCode(mTag);
             _hash = 31 * _hash + Objects.hashCode(mHistoricalOps);
             return _hash;
         }
@@ -5701,10 +5851,10 @@
             // void parcelFieldName(Parcel dest, int flags) { ... }
 
             byte flg = 0;
-            if (mFeatureId != null) flg |= 0x1;
+            if (mTag != null) flg |= 0x1;
             if (mHistoricalOps != null) flg |= 0x2;
             dest.writeByte(flg);
-            if (mFeatureId != null) dest.writeString(mFeatureId);
+            if (mTag != null) dest.writeString(mTag);
             if (mHistoricalOps != null) dest.writeMap(mHistoricalOps);
         }
 
@@ -5715,35 +5865,35 @@
         /** @hide */
         @SuppressWarnings({"unchecked", "RedundantCast"})
         @DataClass.Generated.Member
-        /* package-private */ HistoricalFeatureOps(@NonNull Parcel in) {
+        /* package-private */ AttributedHistoricalOps(@NonNull Parcel in) {
             // You can override field unparcelling by defining methods like:
             // static FieldType unparcelFieldName(Parcel in) { ... }
 
             byte flg = in.readByte();
-            String featureId = (flg & 0x1) == 0 ? null : in.readString();
+            String attributionTag = (flg & 0x1) == 0 ? null : in.readString();
             ArrayMap<String,HistoricalOp> historicalOps = null;
             if ((flg & 0x2) != 0) {
                 historicalOps = new ArrayMap();
                 in.readMap(historicalOps, HistoricalOp.class.getClassLoader());
             }
 
-            this.mFeatureId = featureId;
+            this.mTag = attributionTag;
             this.mHistoricalOps = historicalOps;
 
             // onConstructed(); // You can define this method to get a callback
         }
 
         @DataClass.Generated.Member
-        public static final @NonNull Parcelable.Creator<HistoricalFeatureOps> CREATOR
-                = new Parcelable.Creator<HistoricalFeatureOps>() {
+        public static final @NonNull Parcelable.Creator<AttributedHistoricalOps> CREATOR
+                = new Parcelable.Creator<AttributedHistoricalOps>() {
             @Override
-            public HistoricalFeatureOps[] newArray(int size) {
-                return new HistoricalFeatureOps[size];
+            public AttributedHistoricalOps[] newArray(int size) {
+                return new AttributedHistoricalOps[size];
             }
 
             @Override
-            public HistoricalFeatureOps createFromParcel(@NonNull Parcel in) {
-                return new HistoricalFeatureOps(in);
+            public AttributedHistoricalOps createFromParcel(@NonNull Parcel in) {
+                return new AttributedHistoricalOps(in);
             }
         };
 
@@ -5752,7 +5902,7 @@
                 time = 1578113234821L,
                 codegenVersion = "1.0.14",
                 sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
-                inputSignatures = "private final @android.annotation.Nullable java.lang.String mFeatureId\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.app.HistoricalOp> mHistoricalOps\nprivate @android.annotation.Nullable android.app.HistoricalFeatureOps splice(double)\nprivate  void merge(android.app.HistoricalFeatureOps)\nprivate  void filter(java.lang.String[],int,double)\nprivate  boolean isEmpty()\nprivate  void increaseAccessCount(int,int,int,long)\nprivate  void increaseRejectCount(int,int,int,long)\nprivate  void increaseAccessDuration(int,int,int,long)\npublic @android.annotation.IntRange(from=0L) int getOpCount()\npublic @android.annotation.NonNull android.app.HistoricalOp getOpAt(int)\npublic @android.annotation.Nullable android.app.HistoricalOp getOp(java.lang.String)\nprivate  void accept(android.app.HistoricalOpsVisitor)\nprivate @android.annotation.NonNull android.app.HistoricalOp getOrCreateHistoricalOp(int)\nclass HistoricalFeatureOps extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genHiddenCopyConstructor=true)")
+                inputSignatures = "private final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.app.HistoricalOp> mHistoricalOps\nprivate @android.annotation.Nullable android.app.HistoricalAttributionOps splice(double)\nprivate  void merge(android.app.HistoricalAttributionOps)\nprivate  void filter(java.lang.String[],int,double)\nprivate  boolean isEmpty()\nprivate  void increaseAccessCount(int,int,int,long)\nprivate  void increaseRejectCount(int,int,int,long)\nprivate  void increaseAccessDuration(int,int,int,long)\npublic @android.annotation.IntRange(from=0L) int getOpCount()\npublic @android.annotation.NonNull android.app.HistoricalOp getOpAt(int)\npublic @android.annotation.Nullable android.app.HistoricalOp getOp(java.lang.String)\nprivate  void accept(android.app.HistoricalOpsVisitor)\nprivate @android.annotation.NonNull android.app.HistoricalOp getOrCreateHistoricalOp(int)\nclass HistoricalAttributionOps extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genHiddenCopyConstructor=true)")
         @Deprecated
         private void __metadata() {}
         */
@@ -5886,6 +6036,11 @@
             return mOp;
         }
 
+        /** @hide */
+        public int getLoggingOpCode() {
+            return AppOpsManager.opToLoggingId(mOp);
+        }
+
         /**
          * Gets the number times the op was accessed (performed) in the foreground.
          *
@@ -6428,7 +6583,7 @@
         Objects.requireNonNull(executor, "executor cannot be null");
         Objects.requireNonNull(callback, "callback cannot be null");
         try {
-            mService.getHistoricalOps(request.mUid, request.mPackageName, request.mFeatureId,
+            mService.getHistoricalOps(request.mUid, request.mPackageName, request.mAttributionTag,
                     request.mOpNames, request.mFilter, request.mBeginTimeMillis,
                     request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
@@ -6468,8 +6623,9 @@
         Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
-                    request.mFeatureId, request.mOpNames, request.mFilter, request.mBeginTimeMillis,
-                    request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
+                    request.mAttributionTag, request.mOpNames, request.mFilter,
+                    request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
+                    new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
                 try {
@@ -7059,8 +7215,8 @@
      * @param op The operation to note.  One of the OPSTR_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code
-     * null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+     * null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7070,8 +7226,8 @@
      * @throws SecurityException If the app has been configured to crash on this op.
      */
     public int noteOp(@NonNull String op, int uid, @Nullable String packageName,
-            @Nullable String featureId, @Nullable String message) {
-        return noteOp(strOpToOp(op), uid, packageName, featureId, message);
+            @Nullable String attributionTag, @Nullable String message) {
+        return noteOp(strOpToOp(op), uid, packageName, attributionTag, message);
     }
 
     /**
@@ -7087,7 +7243,8 @@
      * @param op The operation to note.  One of the OP_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The feature in the app or {@code null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+     * null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7098,9 +7255,9 @@
      *
      * @hide
      */
-    public int noteOp(int op, int uid, @Nullable String packageName, @Nullable String featureId,
-            @Nullable String message) {
-        final int mode = noteOpNoThrow(op, uid, packageName, featureId, message);
+    public int noteOp(int op, int uid, @Nullable String packageName,
+            @Nullable String attributionTag, @Nullable String message) {
+        final int mode = noteOpNoThrow(op, uid, packageName, attributionTag, message);
         if (mode == MODE_ERRORED) {
             throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
         }
@@ -7135,8 +7292,8 @@
      * @param op The operation to note.  One of the OPSTR_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code
-     * null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+     * null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7144,8 +7301,8 @@
      * causing the app to crash).
      */
     public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
-            @Nullable String featureId, @Nullable String message) {
-        return noteOpNoThrow(strOpToOp(op), uid, packageName, featureId, message);
+            @Nullable String attributionTag, @Nullable String message) {
+        return noteOpNoThrow(strOpToOp(op), uid, packageName, attributionTag, message);
     }
 
     /**
@@ -7155,7 +7312,8 @@
      * @param op The operation to note.  One of the OP_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The feature in the app or {@code null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+     * null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7165,7 +7323,7 @@
      * @hide
      */
     public int noteOpNoThrow(int op, int uid, @Nullable String packageName,
-            @Nullable String featureId, @Nullable String message) {
+            @Nullable String attributionTag, @Nullable String message) {
         try {
             collectNoteOpCallsForValidation(op);
             int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
@@ -7176,14 +7334,14 @@
                 }
             }
 
-            int mode = mService.noteOperation(op, uid, packageName, featureId,
+            int mode = mService.noteOperation(op, uid, packageName, attributionTag,
                     collectionMode == COLLECT_ASYNC, message);
 
             if (mode == MODE_ALLOWED) {
                 if (collectionMode == COLLECT_SELF) {
-                    collectNotedOpForSelf(op, featureId);
+                    collectNotedOpForSelf(op, attributionTag);
                 } else if (collectionMode == COLLECT_SYNC) {
-                    collectNotedOpSync(op, featureId);
+                    collectNotedOpSync(op, attributionTag);
                 }
             }
 
@@ -7223,8 +7381,8 @@
      * @param op The operation to note. One of the OP_* constants.
      * @param proxiedPackageName The name of the application calling into the proxy application.
      * @param proxiedUid The uid of the proxied application
-     * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
-     *                           feature
+     * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+     * attribution tag} or {@code null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
@@ -7236,8 +7394,8 @@
      * @hide
      */
     public int noteProxyOp(int op, @Nullable String proxiedPackageName, int proxiedUid,
-            @Nullable String proxiedFeatureId, @Nullable String message) {
-        int mode = noteProxyOpNoThrow(op, proxiedPackageName, proxiedUid, proxiedFeatureId,
+            @Nullable String proxiedAttributionTag, @Nullable String message) {
+        int mode = noteProxyOpNoThrow(op, proxiedPackageName, proxiedUid, proxiedAttributionTag,
                 message);
         if (mode == MODE_ERRORED) {
             throw new SecurityException("Proxy package " + mContext.getOpPackageName()
@@ -7256,8 +7414,8 @@
      * @param op The operation to note. One of the OPSTR_* constants.
      * @param proxiedPackageName The name of the application calling into the proxy application.
      * @param proxiedUid The uid of the proxied application
-     * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
-     *                           feature
+     * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+     * attribution tag} or {@code null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
@@ -7267,8 +7425,8 @@
      * op.
      */
     public int noteProxyOp(@NonNull String op, @Nullable String proxiedPackageName, int proxiedUid,
-            @Nullable String proxiedFeatureId, @Nullable String message) {
-        return noteProxyOp(strOpToOp(op), proxiedPackageName, proxiedUid, proxiedFeatureId,
+            @Nullable String proxiedAttributionTag, @Nullable String message) {
+        return noteProxyOp(strOpToOp(op), proxiedPackageName, proxiedUid, proxiedAttributionTag,
                 message);
     }
 
@@ -7299,14 +7457,14 @@
      * @param op The op to note
      * @param proxiedPackageName The package to note the op for
      * @param proxiedUid The uid the package belongs to
-     * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
-     *                           feature
+     * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+     * attribution tag} or {@code null} for default attribution
      * @param message A message describing the reason the op was noted
      */
     public int noteProxyOpNoThrow(@NonNull String op, @Nullable String proxiedPackageName,
-            int proxiedUid, @Nullable String proxiedFeatureId, @Nullable String message) {
+            int proxiedUid, @Nullable String proxiedAttributionTag, @Nullable String message) {
         return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName, proxiedUid,
-                proxiedFeatureId, message);
+                proxiedAttributionTag, message);
     }
 
     /**
@@ -7317,14 +7475,14 @@
      * @param proxiedPackageName The package to note the op for or {@code null} if the op should be
      *                           noted for the "android" package
      * @param proxiedUid The uid the package belongs to
-     * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
-     *                           feature
+     * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+     * attribution tag} or {@code null} for default attribution
      * @param message A message describing the reason the op was noted
      *
      * @hide
      */
     public int noteProxyOpNoThrow(int op, @Nullable String proxiedPackageName, int proxiedUid,
-            @Nullable String proxiedFeatureId, @Nullable String message) {
+            @Nullable String proxiedAttributionTag, @Nullable String message) {
         int myUid = Process.myUid();
 
         try {
@@ -7338,17 +7496,17 @@
             }
 
             int mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
-                    proxiedFeatureId, myUid, mContext.getOpPackageName(),
-                    mContext.getFeatureId(), collectionMode == COLLECT_ASYNC, message);
+                    proxiedAttributionTag, myUid, mContext.getOpPackageName(),
+                    mContext.getAttributionTag(), collectionMode == COLLECT_ASYNC, message);
 
             if (mode == MODE_ALLOWED) {
                 if (collectionMode == COLLECT_SELF) {
-                    collectNotedOpForSelf(op, proxiedFeatureId);
+                    collectNotedOpForSelf(op, proxiedAttributionTag);
                 } else if (collectionMode == COLLECT_SYNC
                         // Only collect app-ops when the proxy is trusted
                         && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
                         myUid) == PackageManager.PERMISSION_GRANTED) {
-                    collectNotedOpSync(op, proxiedFeatureId);
+                    collectNotedOpSync(op, proxiedAttributionTag);
                 }
             }
 
@@ -7537,8 +7695,8 @@
      * @param op The operation to start.  One of the OPSTR_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code
-     * null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+     * {@code null} for default attribution
      * @param message Description why op was started
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7549,8 +7707,8 @@
      * the package is not in the passed in UID.
      */
     public int startOp(@NonNull String op, int uid, @Nullable String packageName,
-            @Nullable String featureId, @Nullable String message) {
-        return startOp(strOpToOp(op), uid, packageName, false, featureId, message);
+            @Nullable String attributionTag, @Nullable String message) {
+        return startOp(strOpToOp(op), uid, packageName, false, attributionTag, message);
     }
 
     /**
@@ -7559,7 +7717,8 @@
      * @param op The operation to start.  One of the OP_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The feature in the app or {@code null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+     * {@code null} for default attribution
      * @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
      * @param message Description why op was started
      *
@@ -7573,8 +7732,8 @@
      * @hide
      */
     public int startOp(int op, int uid, @Nullable String packageName, boolean startIfModeDefault,
-            @Nullable String featureId, @Nullable String message) {
-        final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault, featureId,
+            @Nullable String attributionTag, @Nullable String message) {
+        final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault, attributionTag,
                 message);
         if (mode == MODE_ERRORED) {
             throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
@@ -7617,7 +7776,8 @@
      * @param op The operation to start.  One of the OP_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The feature in the app or {@code null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+     * {@code null} for default attribution
      * @param message Description why op was started
      *
      * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7625,8 +7785,8 @@
      * causing the app to crash).
      */
     public int startOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
-            @NonNull String featureId, @Nullable String message) {
-        return startOpNoThrow(strOpToOp(op), uid, packageName, false, featureId, message);
+            @NonNull String attributionTag, @Nullable String message) {
+        return startOpNoThrow(strOpToOp(op), uid, packageName, false, attributionTag, message);
     }
 
     /**
@@ -7636,7 +7796,8 @@
      * @param op The operation to start.  One of the OP_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
-     * @param featureId The feature in the app or {@code null} for default feature
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+     * {@code null} for default attribution
      * @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
      * @param message Description why op was started
      *
@@ -7647,7 +7808,7 @@
      * @hide
      */
     public int startOpNoThrow(int op, int uid, @NonNull String packageName,
-            boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
+            boolean startIfModeDefault, @Nullable String attributionTag, @Nullable String message) {
         try {
             collectNoteOpCallsForValidation(op);
             int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
@@ -7659,13 +7820,13 @@
             }
 
             int mode = mService.startOperation(getClientId(), op, uid, packageName,
-                    featureId, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
+                    attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
 
             if (mode == MODE_ALLOWED) {
                 if (collectionMode == COLLECT_SELF) {
-                    collectNotedOpForSelf(op, featureId);
+                    collectNotedOpForSelf(op, attributionTag);
                 } else if (collectionMode == COLLECT_SYNC) {
-                    collectNotedOpSync(op, featureId);
+                    collectNotedOpSync(op, attributionTag);
                 }
             }
 
@@ -7699,8 +7860,8 @@
      * previously passed in when starting the operation.
      */
     public void finishOp(@NonNull String op, int uid, @NonNull String packageName,
-            @Nullable String featureId) {
-        finishOp(strOpToOp(op), uid, packageName, featureId);
+            @Nullable String attributionTag) {
+        finishOp(strOpToOp(op), uid, packageName, attributionTag);
     }
 
     /**
@@ -7721,9 +7882,9 @@
      * @hide
      */
     public void finishOp(int op, int uid, @NonNull String packageName,
-            @Nullable String featureId) {
+            @Nullable String attributionTag) {
         try {
-            mService.finishOperation(getClientId(), op, uid, packageName, featureId);
+            mService.finishOperation(getClientId(), op, uid, packageName, attributionTag);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -7834,15 +7995,15 @@
      * Collect a noted op for the current process.
      *
      * @param op The noted op
-     * @param featureId The feature the op is noted for
+     * @param attributionTag The attribution tag the op is noted for
      */
-    private void collectNotedOpForSelf(int op, @Nullable String featureId) {
+    private void collectNotedOpForSelf(int op, @Nullable String attributionTag) {
         synchronized (sLock) {
             if (sOnOpNotedCallback != null) {
-                sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
+                sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, attributionTag));
             }
         }
-        sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+        sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, attributionTag));
     }
 
     /**
@@ -7851,9 +8012,9 @@
      * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
      *
      * @param op The noted op
-     * @param featureId The feature the op is noted for
+     * @param attributionTag The attribution tag the op is noted for
      */
-    private void collectNotedOpSync(int op, @Nullable String featureId) {
+    private void collectNotedOpSync(int op, @Nullable String attributionTag) {
         // If this is inside of a two-way binder call:
         // We are inside of a two-way binder call. Delivered to caller via
         // {@link #prefixParcelWithAppOpsIfNeeded}
@@ -7863,16 +8024,16 @@
             sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
         }
 
-        long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
-        if (appOpsNotedForFeature == null) {
-            appOpsNotedForFeature = new long[2];
-            appOpsNoted.put(featureId, appOpsNotedForFeature);
+        long[] appOpsNotedForAttribution = appOpsNoted.get(attributionTag);
+        if (appOpsNotedForAttribution == null) {
+            appOpsNotedForAttribution = new long[2];
+            appOpsNoted.put(attributionTag, appOpsNotedForAttribution);
         }
 
         if (op < 64) {
-            appOpsNotedForFeature[0] |= 1L << op;
+            appOpsNotedForAttribution[0] |= 1L << op;
         } else {
-            appOpsNotedForFeature[1] |= 1L << (op - 64);
+            appOpsNotedForAttribution[1] |= 1L << (op - 64);
         }
     }
 
@@ -7953,10 +8114,10 @@
 
         p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER);
 
-        int numFeatureWithNotesAppOps = notedAppOps.size();
-        p.writeInt(numFeatureWithNotesAppOps);
+        int numAttributionWithNotesAppOps = notedAppOps.size();
+        p.writeInt(numAttributionWithNotesAppOps);
 
-        for (int i = 0; i < numFeatureWithNotesAppOps; i++) {
+        for (int i = 0; i < numAttributionWithNotesAppOps; i++) {
             p.writeString(notedAppOps.keyAt(i));
             p.writeLong(notedAppOps.valueAt(i)[0]);
             p.writeLong(notedAppOps.valueAt(i)[1]);
@@ -7974,10 +8135,10 @@
      * @hide
      */
     public static void readAndLogNotedAppops(@NonNull Parcel p) {
-        int numFeaturesWithNotedAppOps = p.readInt();
+        int numAttributionsWithNotedAppOps = p.readInt();
 
-        for (int i = 0; i < numFeaturesWithNotedAppOps; i++) {
-            String featureId = p.readString();
+        for (int i = 0; i < numAttributionsWithNotedAppOps; i++) {
+            String attributionTag = p.readString();
             long[] rawNotedAppOps = new long[2];
             rawNotedAppOps[0] = p.readLong();
             rawNotedAppOps[1] = p.readLong();
@@ -7989,13 +8150,13 @@
                     for (int code = notedAppOps.nextSetBit(0); code != -1;
                             code = notedAppOps.nextSetBit(code + 1)) {
                         if (sOnOpNotedCallback != null) {
-                            sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
+                            sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag));
                         }
                     }
                 }
                 for (int code = notedAppOps.nextSetBit(0); code != -1;
                         code = notedAppOps.nextSetBit(code + 1)) {
-                    sMessageCollector.onNoted(new SyncNotedAppOp(code, featureId));
+                    sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag));
                 }
             }
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 87d33a9..18df401 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -840,6 +840,27 @@
     }
 
     @Override
+    public boolean setAutoRevokeWhitelisted(
+            @NonNull String packageName, boolean whitelisted) {
+        try {
+            final int userId = getUserId();
+            return mPermissionManager.setAutoRevokeWhitelisted(packageName, whitelisted, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public boolean isAutoRevokeWhitelisted(@NonNull String packageName) {
+        try {
+            final int userId = getUserId();
+            return mPermissionManager.isAutoRevokeWhitelisted(packageName, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
             @NonNull String permName, @PermissionWhitelistFlags int flags) {
         try {
@@ -3337,6 +3358,15 @@
         }
     }
 
+    @Override
+    public boolean isAutoRevokeWhitelisted() {
+        try {
+            return mPM.isAutoRevokeWhitelisted(mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     public void setMimeGroup(String mimeGroup, Set<String> mimeTypes) {
         try {
             mPM.setMimeGroup(mContext.getPackageName(), mimeGroup,
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 4d955db..b0c2762c 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -48,8 +48,8 @@
     /** Uid that noted the op */
     private final @IntRange(from = 0) int mNotingUid;
 
-    /** {@link android.content.Context#createFeatureContext Feature} in the app */
-    private final @Nullable String mFeatureId;
+    /** {@link android.content.Context#createAttributionContext attribution tag} */
+    private final @Nullable String mAttributionTag;
 
     /** Message associated with the noteOp. This message is set by the app noting the op */
     private final @NonNull String mMessage;
@@ -92,8 +92,8 @@
      *   Op that was noted
      * @param notingUid
      *   Uid that noted the op
-     * @param featureId
-     *   {@link android.content.Context#createFeatureContext Feature} in the app
+     * @param attributionTag
+     *   {@link android.content.Context#createAttributionContext attribution tag}
      * @param message
      *   Message associated with the noteOp. This message is set by the app noting the op
      * @param time
@@ -104,7 +104,7 @@
     public AsyncNotedAppOp(
             @IntRange(from = 0) int opCode,
             @IntRange(from = 0) int notingUid,
-            @Nullable String featureId,
+            @Nullable String attributionTag,
             @NonNull String message,
             @CurrentTimeMillisLong long time) {
         this.mOpCode = opCode;
@@ -115,7 +115,7 @@
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mNotingUid,
                 "from", 0);
-        this.mFeatureId = featureId;
+        this.mAttributionTag = attributionTag;
         this.mMessage = message;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessage);
@@ -135,11 +135,11 @@
     }
 
     /**
-     * {@link android.content.Context#createFeatureContext Feature} in the app
+     * {@link android.content.Context#createAttributionContext attribution tag}
      */
     @DataClass.Generated.Member
-    public @Nullable String getFeatureId() {
-        return mFeatureId;
+    public @Nullable String getAttributionTag() {
+        return mAttributionTag;
     }
 
     /**
@@ -173,7 +173,7 @@
         return true
                 && mOpCode == that.mOpCode
                 && mNotingUid == that.mNotingUid
-                && java.util.Objects.equals(mFeatureId, that.mFeatureId)
+                && java.util.Objects.equals(mAttributionTag, that.mAttributionTag)
                 && java.util.Objects.equals(mMessage, that.mMessage)
                 && mTime == that.mTime;
     }
@@ -187,7 +187,7 @@
         int _hash = 1;
         _hash = 31 * _hash + mOpCode;
         _hash = 31 * _hash + mNotingUid;
-        _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureId);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
         _hash = 31 * _hash + java.util.Objects.hashCode(mMessage);
         _hash = 31 * _hash + Long.hashCode(mTime);
         return _hash;
@@ -200,11 +200,11 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
-        if (mFeatureId != null) flg |= 0x4;
+        if (mAttributionTag != null) flg |= 0x4;
         dest.writeByte(flg);
         dest.writeInt(mOpCode);
         dest.writeInt(mNotingUid);
-        if (mFeatureId != null) dest.writeString(mFeatureId);
+        if (mAttributionTag != null) dest.writeString(mAttributionTag);
         dest.writeString(mMessage);
         dest.writeLong(mTime);
     }
@@ -223,7 +223,7 @@
         byte flg = in.readByte();
         int opCode = in.readInt();
         int notingUid = in.readInt();
-        String featureId = (flg & 0x4) == 0 ? null : in.readString();
+        String attributionTag = (flg & 0x4) == 0 ? null : in.readString();
         String message = in.readString();
         long time = in.readLong();
 
@@ -235,7 +235,7 @@
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mNotingUid,
                 "from", 0);
-        this.mFeatureId = featureId;
+        this.mAttributionTag = attributionTag;
         this.mMessage = message;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessage);
@@ -261,10 +261,10 @@
     };
 
     @DataClass.Generated(
-            time = 1583866178330L,
+            time = 1583866239013L,
             codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
-            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)")
+            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 mAttributionTag\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/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2873b10..9ccfe8d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -219,8 +219,8 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mOpPackageName;
 
-    /** If of feature this context is for */
-    private final @Nullable String mFeatureId;
+    /** Attribution tag of this context */
+    private final @Nullable String mAttributionTag;
 
     private final @NonNull ResourcesManager mResourcesManager;
     @UnsupportedAppUsage
@@ -421,8 +421,8 @@
 
     /** @hide */
     @Override
-    public @Nullable String getFeatureId() {
-        return mFeatureId;
+    public @Nullable String getAttributionTag() {
+        return mAttributionTag;
     }
 
     @Override
@@ -1026,10 +1026,10 @@
     public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
         try {
             ActivityTaskManager.getService().startActivityAsUser(
-                mMainThread.getApplicationThread(), getBasePackageName(), getFeatureId(), intent,
-                intent.resolveTypeIfNeeded(getContentResolver()),
-                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
-                user.getIdentifier());
+                    mMainThread.getApplicationThread(), getBasePackageName(), getAttributionTag(),
+                    intent, intent.resolveTypeIfNeeded(getContentResolver()),
+                    null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
+                    user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1109,9 +1109,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
-                    getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+                    false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1126,9 +1126,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
-                    null, false, false, getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions,
+                    AppOpsManager.OP_NONE, null, false, false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1141,9 +1141,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
-                    null, false, false, getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions,
+                    AppOpsManager.OP_NONE, null, false, false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1156,9 +1156,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
-                    null, false, false, user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions,
+                    AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1173,9 +1173,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
-                    options, false, false, getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions,
+                    AppOpsManager.OP_NONE, options, false, false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1190,9 +1190,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
-                    getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
+                    false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1207,9 +1207,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
-                    null, true, false, getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions,
+                    AppOpsManager.OP_NONE, null, true, false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1270,8 +1270,8 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
-                initialCode, initialData, initialExtras, receiverPermissions, appOp,
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
                     options, true, false, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1284,9 +1284,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
-                    user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+                    false, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1307,9 +1307,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
-                    options, false, false, user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions,
+                    AppOpsManager.OP_NONE, options, false, false, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1324,9 +1324,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                    mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
-                    user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
+                    false, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1375,9 +1375,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
-                initialCode, initialData, initialExtras, receiverPermissions,
-                    appOp, options, true, false, user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
+                    options, true, false, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1416,9 +1416,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
-                getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+                    true, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1452,9 +1452,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
-                initialCode, initialData, initialExtras, null,
-                    AppOpsManager.OP_NONE, null, true, true, getUserId());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
+                    true, true, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1484,9 +1484,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
-                    user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+                    true, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1499,9 +1499,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
-                user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
+                    false, true, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1534,9 +1534,9 @@
         try {
             intent.prepareToLeaveProcess(this);
             ActivityManager.getService().broadcastIntentWithFeature(
-                mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
-                initialCode, initialData, initialExtras, null,
-                    AppOpsManager.OP_NONE, null, true, true, user.getIdentifier());
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
+                    true, true, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1620,7 +1620,7 @@
         }
         try {
             final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
-                    mMainThread.getApplicationThread(), mBasePackageName, getFeatureId(), rd,
+                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
                     filter, broadcastPermission, userId, flags);
             if (intent != null) {
                 intent.setExtrasClassLoader(getClassLoader());
@@ -1696,7 +1696,7 @@
             ComponentName cn = ActivityManager.getService().startService(
                     mMainThread.getApplicationThread(), service,
                     service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
-                    getOpPackageName(), getFeatureId(), user.getIdentifier());
+                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
             if (cn != null) {
                 if (cn.getPackageName().equals("!")) {
                     throw new SecurityException(
@@ -1899,8 +1899,9 @@
     public Object getSystemService(String name) {
         // Check incorrect Context usage.
         if (isUiComponent(name) && !isUiContext() && vmIncorrectContextUseEnabled()) {
-            final String errorMessage = "Tried to access visual service " + name
-                    + " from a non-visual Context.";
+            final String errorMessage = "Tried to access visual service "
+                    + SystemServiceRegistry.getSystemServiceClassName(name)
+                    + " from a non-visual Context. ";
             final String message = "Visual services, such as WindowManager, WallpaperService or "
                     + "LayoutInflater should be accessed from Activity or other visual Context. "
                     + "Use an Activity or a Context created with "
@@ -2285,14 +2286,14 @@
         if (packageName.equals("system") || packageName.equals("android")) {
             // The system resources are loaded in every application, so we can safely copy
             // the context without reloading Resources.
-            return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, null,
+            return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, null,
                     mToken, user, flags, null, null);
         }
 
         LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
         if (pi != null) {
-            ContextImpl c = new ContextImpl(this, mMainThread, pi, mFeatureId, null,
+            ContextImpl c = new ContextImpl(this, mMainThread, pi, mAttributionTag, null,
                     mToken, user, flags, null, null);
 
             final int displayId = getDisplayId();
@@ -2329,7 +2330,7 @@
         final String[] paths = mPackageInfo.getSplitPaths(splitName);
 
         final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
-                mFeatureId, splitName, mToken, mUser, mFlags, classLoader, null);
+                mAttributionTag, splitName, mToken, mUser, mFlags, classLoader, null);
 
         final int displayId = getDisplayId();
 
@@ -2353,7 +2354,7 @@
             throw new IllegalArgumentException("overrideConfiguration must not be null");
         }
 
-        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
                 mSplitName, mToken, mUser, mFlags, mClassLoader, null);
 
         final int displayId = getDisplayId();
@@ -2370,7 +2371,7 @@
             throw new IllegalArgumentException("display must not be null");
         }
 
-        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
                 mSplitName, mToken, mUser, mFlags, mClassLoader, null);
 
         final int displayId = display.getDisplayId();
@@ -2394,7 +2395,7 @@
     }
 
     ContextImpl createBaseWindowContext(IBinder token) {
-        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
                 mSplitName, token, mUser, mFlags, mClassLoader, null);
         context.mIsUiContext = true;
 
@@ -2420,8 +2421,8 @@
     }
 
     @Override
-    public @NonNull Context createFeatureContext(@Nullable String featureId) {
-        return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName,
+    public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
+        return new ContextImpl(this, mMainThread, mPackageInfo, attributionTag, mSplitName,
                 mToken, mUser, mFlags, mClassLoader, null);
     }
 
@@ -2429,7 +2430,7 @@
     public Context createDeviceProtectedStorageContext() {
         final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
                 | Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
-        return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
+        return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName,
                 mToken, mUser, flags, mClassLoader, null);
     }
 
@@ -2437,7 +2438,7 @@
     public Context createCredentialProtectedStorageContext() {
         final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
                 | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
-        return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
+        return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName,
                 mToken, mUser, flags, mClassLoader, null);
     }
 
@@ -2700,7 +2701,7 @@
     }
 
     private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
-            @NonNull LoadedApk packageInfo, @Nullable String featureId,
+            @NonNull LoadedApk packageInfo, @Nullable String attributionTag,
             @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user,
             int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
         mOuterContext = this;
@@ -2754,7 +2755,7 @@
         }
 
         mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
-        mFeatureId = featureId;
+        mAttributionTag = attributionTag;
         mContentResolver = new ApplicationContentResolver(this, mainThread);
     }
 
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 18932c6..818a121 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1720,11 +1720,10 @@
         try {
             intent.migrateExtraStreamToClipData();
             intent.prepareToLeaveProcess(who);
-            int result = ActivityTaskManager.getService()
-                .startActivity(whoThread, who.getBasePackageName(), who.getFeatureId(), intent,
-                        intent.resolveTypeIfNeeded(who.getContentResolver()),
-                        token, target != null ? target.mEmbeddedID : null,
-                        requestCode, 0, null, options);
+            int result = ActivityTaskManager.getService().startActivity(whoThread,
+                    who.getBasePackageName(), who.getAttributionTag(), intent,
+                    intent.resolveTypeIfNeeded(who.getContentResolver()), token,
+                    target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -1793,9 +1792,9 @@
                 intents[i].prepareToLeaveProcess(who);
                 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
             }
-            int result = ActivityTaskManager.getService()
-                .startActivities(whoThread, who.getBasePackageName(), who.getFeatureId(), intents,
-                        resolvedTypes, token, options, userId);
+            int result = ActivityTaskManager.getService().startActivities(whoThread,
+                    who.getBasePackageName(), who.getAttributionTag(), intents, resolvedTypes,
+                    token, options, userId);
             checkStartActivityResult(result, intents[0]);
             return result;
         } catch (RemoteException e) {
@@ -1860,10 +1859,10 @@
         try {
             intent.migrateExtraStreamToClipData();
             intent.prepareToLeaveProcess(who);
-            int result = ActivityTaskManager.getService()
-                .startActivity(whoThread, who.getBasePackageName(), who.getFeatureId(), intent,
-                        intent.resolveTypeIfNeeded(who.getContentResolver()),
-                        token, target, requestCode, 0, null, options);
+            int result = ActivityTaskManager.getService().startActivity(whoThread,
+                    who.getBasePackageName(), who.getAttributionTag(), intent,
+                    intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
+                    requestCode, 0, null, options);
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -1927,11 +1926,10 @@
         try {
             intent.migrateExtraStreamToClipData();
             intent.prepareToLeaveProcess(who);
-            int result = ActivityTaskManager.getService()
-                .startActivityAsUser(whoThread, who.getBasePackageName(), who.getFeatureId(),
-                        intent, intent.resolveTypeIfNeeded(who.getContentResolver()),
-                        token, resultWho,
-                        requestCode, 0, null, options, user.getIdentifier());
+            int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
+                    who.getBasePackageName(), who.getAttributionTag(), intent,
+                    intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
+                    requestCode, 0, null, options, user.getIdentifier());
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -2022,7 +2020,7 @@
             intent.migrateExtraStreamToClipData();
             intent.prepareToLeaveProcess(who);
             int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
-                    who.getFeatureId(), intent,
+                    who.getAttributionTag(), intent,
                     intent.resolveTypeIfNeeded(who.getContentResolver()), options);
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 32e7d84..864af3d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -21,6 +21,7 @@
 import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
 
 import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
+import static com.android.internal.widget.ConversationLayout.CONVERSATION_LAYOUT_ENABLED;
 
 import android.annotation.ColorInt;
 import android.annotation.DimenRes;
@@ -389,6 +390,7 @@
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_text);
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_inbox);
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_messaging);
+        STANDARD_LAYOUTS.add(R.layout.notification_template_material_conversation);
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_media);
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_media);
         STANDARD_LAYOUTS.add(R.layout.notification_template_header);
@@ -5138,7 +5140,7 @@
             int color = isColorized(p) ? getPrimaryTextColor(p) : getSecondaryTextColor(p);
             contentView.setDrawableTint(R.id.expand_button, false, color,
                     PorterDuff.Mode.SRC_ATOP);
-            contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
+            contentView.setInt(R.id.expand_button, "setOriginalNotificationColor",
                     color);
         }
 
@@ -6116,7 +6118,9 @@
         }
 
         private int getMessagingLayoutResource() {
-            return R.layout.notification_template_material_messaging;
+            return CONVERSATION_LAYOUT_ENABLED
+                    ? R.layout.notification_template_material_conversation
+                    : R.layout.notification_template_material_messaging;
         }
 
         private int getActionLayoutResource() {
@@ -6221,6 +6225,17 @@
             }
             return loadHeaderAppName();
         }
+
+        /**
+         * @return if this builder uses a template
+         *
+         * @hide
+         */
+        public boolean usesTemplate() {
+            return (mN.contentView == null && mN.headsUpContentView == null
+                    && mN.bigContentView == null)
+                    || (mStyle != null && mStyle.displayCustomViewInline());
+        }
     }
 
     /**
@@ -7379,7 +7394,7 @@
         public RemoteViews makeContentView(boolean increasedHeight) {
             mBuilder.mOriginalActions = mBuilder.mActions;
             mBuilder.mActions = new ArrayList<>();
-            RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */,
+            RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
                     false /* hideLargeIcon */);
             mBuilder.mActions = mBuilder.mOriginalActions;
             mBuilder.mOriginalActions = null;
@@ -7469,19 +7484,18 @@
          */
         @Override
         public RemoteViews makeBigContentView() {
-            return makeMessagingView(false /* displayImagesAtEnd */, true /* hideLargeIcon */);
+            return makeMessagingView(false /* isCollapsed */, true /* hideLargeIcon */);
         }
 
         /**
          * Create a messaging layout.
          *
-         * @param displayImagesAtEnd should images be displayed at the end of the content instead
-         *                           of inline.
+         * @param isCollapsed Should this use the collapsed layout
          * @param hideRightIcons Should the reply affordance be shown at the end of the notification
          * @return the created remoteView.
          */
         @NonNull
-        private RemoteViews makeMessagingView(boolean displayImagesAtEnd, boolean hideRightIcons) {
+        private RemoteViews makeMessagingView(boolean isCollapsed, boolean hideRightIcons) {
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
@@ -7512,9 +7526,11 @@
                     p,
                     bindResult);
             addExtras(mBuilder.mN.extras);
-            // also update the end margin if there is an image
-            contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
-                    bindResult.getIconMarginEnd());
+            if (!CONVERSATION_LAYOUT_ENABLED) {
+                // also update the end margin if there is an image
+                contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
+                        bindResult.getIconMarginEnd());
+            }
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
                     mBuilder.isColorized(p) ? mBuilder.getPrimaryTextColor(p)
                             : mBuilder.resolveContrastColor(p));
@@ -7522,14 +7538,21 @@
                     mBuilder.getPrimaryTextColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content, "setMessageTextColor",
                     mBuilder.getSecondaryTextColor(p));
-            contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
-                    displayImagesAtEnd);
+            contentView.setInt(R.id.status_bar_latest_event_content,
+                    "setNotificationBackgroundColor",
+                    mBuilder.resolveBackgroundColor(p));
+            contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed",
+                    isCollapsed);
             contentView.setIcon(R.id.status_bar_latest_event_content, "setAvatarReplacement",
                     avatarReplacement);
             contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement",
                     nameReplacement);
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsOneToOne",
                     isOneToOne);
+            contentView.setCharSequence(R.id.status_bar_latest_event_content,
+                    "setConversationTitle", conversationTitle);
+            contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
+                    mBuilder.mN.mLargeIcon);
             contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
                     mBuilder.mN.extras);
             return contentView;
@@ -7590,9 +7613,11 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */,
+            RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
                     true /* hideLargeIcon */);
-            remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
+            if (!CONVERSATION_LAYOUT_ENABLED) {
+                remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
+            }
             return remoteViews;
         }
 
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f68c929..792f840 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -355,8 +355,8 @@
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
-                    null, null, requestCode, new Intent[] { intent },
+                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+                    context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
                     flags, options, context.getUserId());
             return target != null ? new PendingIntent(target) : null;
@@ -381,8 +381,8 @@
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
-                    null, null, requestCode, new Intent[] { intent },
+                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+                    context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
                     flags, options, user.getIdentifier());
             return target != null ? new PendingIntent(target) : null;
@@ -498,9 +498,9 @@
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
-                    null, null, requestCode, intents, resolvedTypes, flags, options,
-                    context.getUserId());
+                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+                    context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
+                    flags, options, context.getUserId());
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -524,8 +524,8 @@
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
-                    null, null, requestCode, intents, resolvedTypes,
+                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+                    context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
                     flags, options, user.getIdentifier());
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
@@ -576,8 +576,8 @@
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_BROADCAST, packageName, context.getFeatureId(),
-                    null, null, requestCode, new Intent[] { intent },
+                    ActivityManager.INTENT_SENDER_BROADCAST, packageName,
+                    context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
                     flags, null, userHandle.getIdentifier());
             return target != null ? new PendingIntent(target) : null;
@@ -655,7 +655,7 @@
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    serviceKind, packageName, context.getFeatureId(),
+                    serviceKind, packageName, context.getAttributionTag(),
                     null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
                     flags, null, context.getUserId());
diff --git a/core/java/android/app/RuntimeAppOpAccessMessage.java b/core/java/android/app/RuntimeAppOpAccessMessage.java
index a81b8e7..a19f815 100644
--- a/core/java/android/app/RuntimeAppOpAccessMessage.java
+++ b/core/java/android/app/RuntimeAppOpAccessMessage.java
@@ -44,7 +44,7 @@
     /** Name of package for which runtime app op access message was collected */
     private final @NonNull String mPackageName;
     /** Feature of package for which runtime app op access message was collected */
-    private final @Nullable String mFeatureId;
+    private final @Nullable String mAttributionTag;
     /** Message collected (including stacktrace for synchronous ops) */
     private final @NonNull String mMessage;
     /** Sampling strategy used to collect this message. */
@@ -63,8 +63,8 @@
      *   Op code of operation access which was collected
      * @param packageName
      *   Name of package for which runtime app op access message was collected
-     * @param featureId
-     *   Feature of package for which runtime app op access message was collected
+     * @param attributionTag
+     *   Attribution tag for which runtime app op access message was collected
      * @param message
      *   Message collected (including stacktrace for synchronous ops)
      * @param samplingStrategy
@@ -75,7 +75,7 @@
             @IntRange(from = 0L) int uid,
             @IntRange(from = 0L) int opCode,
             @NonNull String packageName,
-            @Nullable String featureId,
+            @Nullable String attributionTag,
             @NonNull String message,
             @AppOpsManager.SamplingStrategy int samplingStrategy) {
         this.mUid = uid;
@@ -90,7 +90,7 @@
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPackageName);
-        this.mFeatureId = featureId;
+        this.mAttributionTag = attributionTag;
         this.mMessage = message;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessage);
@@ -134,11 +134,11 @@
     }
 
     /**
-     * Feature of package for which runtime app op access message was collected
+     * Attribution tag for which runtime app op access message was collected
      */
     @DataClass.Generated.Member
-    public @Nullable String getFeatureId() {
-        return mFeatureId;
+    public @Nullable String getAttributionTag() {
+        return mAttributionTag;
     }
 
     /**
@@ -164,12 +164,12 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
-        if (mFeatureId != null) flg |= 0x8;
+        if (mAttributionTag != null) flg |= 0x8;
         dest.writeByte(flg);
         dest.writeInt(mUid);
         dest.writeInt(mOpCode);
         dest.writeString(mPackageName);
-        if (mFeatureId != null) dest.writeString(mFeatureId);
+        if (mAttributionTag != null) dest.writeString(mAttributionTag);
         dest.writeString(mMessage);
         dest.writeInt(mSamplingStrategy);
     }
@@ -189,7 +189,7 @@
         int uid = in.readInt();
         int opCode = in.readInt();
         String packageName = in.readString();
-        String featureId = (flg & 0x8) == 0 ? null : in.readString();
+        String attributionTag = (flg & 0x8) == 0 ? null : in.readString();
         String message = in.readString();
         int samplingStrategy = in.readInt();
 
@@ -205,7 +205,7 @@
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPackageName);
-        this.mFeatureId = featureId;
+        this.mAttributionTag = attributionTag;
         this.mMessage = message;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mMessage);
@@ -234,7 +234,7 @@
             time = 1581517099127L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/app/RuntimeAppOpAccessMessage.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.app.AppOpsManager.SamplingStrategy int mSamplingStrategy\npublic @android.annotation.NonNull java.lang.String getOp()\nclass RuntimeAppOpAccessMessage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false)")*/
+            inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.app.AppOpsManager.SamplingStrategy int mSamplingStrategy\npublic @android.annotation.NonNull java.lang.String getOp()\nclass RuntimeAppOpAccessMessage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false)")*/
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index dc8269f..81396fe 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -34,6 +34,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.contentcapture.ContentCaptureManager;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -306,7 +307,8 @@
  * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.java
  *      bind}
  */
-public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
+public abstract class Service extends ContextWrapper implements ComponentCallbacks2,
+        ContentCaptureManager.ContentCaptureClient {
     private static final String TAG = "Service";
 
     /**
@@ -817,8 +819,16 @@
         writer.println("nothing to dump");
     }
 
+    @Override
+    protected void attachBaseContext(Context newBase) {
+        super.attachBaseContext(newBase);
+        if (newBase != null) {
+            newBase.setContentCaptureOptions(getContentCaptureOptions());
+        }
+    }
+
     // ------------------ Internal API ------------------
-    
+
     /**
      * @hide
      */
@@ -835,6 +845,7 @@
         mActivityManager = (IActivityManager)activityManager;
         mStartCompatibility = getApplicationInfo().targetSdkVersion
                 < Build.VERSION_CODES.ECLAIR;
+        setContentCaptureOptions(application.getContentCaptureOptions());
     }
 
     /**
@@ -849,6 +860,18 @@
         return mClassName;
     }
 
+    /** @hide */
+    @Override
+    public final ContentCaptureManager.ContentCaptureClient getContentCaptureClient() {
+        return this;
+    }
+
+    /** @hide */
+    @Override
+    public final ComponentName contentCaptureClientGetComponentName() {
+        return new ComponentName(this, mClassName);
+    }
+
     // set by the thread after the constructor and before onCreate(Bundle icicle) is called.
     @UnsupportedAppUsage
     private ActivityThread mThread = null;
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 42563b5..1329fa4 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -399,7 +399,6 @@
      *                 {@code false}, re-enables expansion of the status bar.
      * @hide
      */
-    @SystemApi
     @TestApi
     @RequiresPermission(android.Manifest.permission.STATUS_BAR)
     public void setDisabledForSimNetworkLock(boolean disabled) {
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index 13b90ca..0a880dc 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -43,24 +43,24 @@
 
     /** op code of synchronous appop noted */
     private final @IntRange(from = 0L, to = AppOpsManager._NUM_OP - 1) int mOpCode;
-    /** featureId of synchronous appop noted */
-    private final @Nullable String mFeatureId;
+    /** attributionTag of synchronous appop noted */
+    private final @Nullable String mAttributionTag;
 
     /**
      * Creates a new SyncNotedAppOp.
      *
      * @param opCode
      *   op code of synchronous appop noted
-     * @param featureId
-     *   featureId of synchronous appop noted
+     * @param attributionTag
+     *   attributionTag of synchronous appop noted
      */
-    public SyncNotedAppOp(@IntRange(from = 0L) int opCode, @Nullable String featureId) {
+    public SyncNotedAppOp(@IntRange(from = 0L) int opCode, @Nullable String attributionTag) {
         this.mOpCode = opCode;
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mOpCode,
                 "from", 0,
                 "to", AppOpsManager._NUM_OP - 1);
-        this.mFeatureId = featureId;
+        this.mAttributionTag = attributionTag;
     }
 
     /**
@@ -84,11 +84,11 @@
 
 
     /**
-     * featureId of synchronous appop noted
+     * attributionTag of synchronous appop noted
      */
     @DataClass.Generated.Member
-    public @Nullable String getFeatureId() {
-        return mFeatureId;
+    public @Nullable String getAttributionTag() {
+        return mAttributionTag;
     }
 
     @Override
@@ -105,7 +105,7 @@
         //noinspection PointlessBooleanExpression
         return true
                 && mOpCode == that.mOpCode
-                && java.util.Objects.equals(mFeatureId, that.mFeatureId);
+                && java.util.Objects.equals(mAttributionTag, that.mAttributionTag);
     }
 
     @Override
@@ -116,7 +116,7 @@
 
         int _hash = 1;
         _hash = 31 * _hash + mOpCode;
-        _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureId);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
         return _hash;
     }
 
@@ -127,10 +127,10 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
-        if (mFeatureId != null) flg |= 0x2;
+        if (mAttributionTag != null) flg |= 0x2;
         dest.writeByte(flg);
         dest.writeInt(mOpCode);
-        if (mFeatureId != null) dest.writeString(mFeatureId);
+        if (mAttributionTag != null) dest.writeString(mAttributionTag);
     }
 
     @Override
@@ -146,14 +146,14 @@
 
         byte flg = in.readByte();
         int opCode = in.readInt();
-        String featureId = (flg & 0x2) == 0 ? null : in.readString();
+        String attributionTag = (flg & 0x2) == 0 ? null : in.readString();
 
         this.mOpCode = opCode;
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mOpCode,
                 "from", 0,
                 "to", AppOpsManager._NUM_OP - 1);
-        this.mFeatureId = featureId;
+        this.mAttributionTag = attributionTag;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -176,7 +176,7 @@
             time = 1579188889960L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/app/SyncNotedAppOp.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\npublic @android.annotation.NonNull java.lang.String getOp()\npublic @android.annotation.SystemApi int getOpCode()\nclass SyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genConstructor=false)")*/
+            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\npublic @android.annotation.NonNull java.lang.String getOp()\npublic @android.annotation.SystemApi int getOpCode()\nclass SyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genConstructor=false)")*/
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index a3bcc9c..e8f30df 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -19,6 +19,7 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ContextImpl.ServiceInitializationState;
 import android.app.admin.DevicePolicyManager;
@@ -227,6 +228,8 @@
             new ArrayMap<Class<?>, String>();
     private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
             new ArrayMap<String, ServiceFetcher<?>>();
+    private static final Map<String, String> SYSTEM_SERVICE_CLASS_NAMES = new ArrayMap<>();
+
     private static int sServiceCacheSize;
 
     private static volatile boolean sInitializing;
@@ -1389,6 +1392,19 @@
             @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
         SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
         SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
+        SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
+    }
+
+    /**
+     * Returns system service class name by system service name. This method is mostly an inverse of
+     * {@link #getSystemServiceName(Class)}
+     *
+     * @return system service class name. {@code null} if service name is invalid.
+     * @hide
+     */
+    @Nullable
+    public static String getSystemServiceClassName(@NonNull String name) {
+        return SYSTEM_SERVICE_CLASS_NAMES.get(name);
     }
 
     /**
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 1a84547..b2dd0ef 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -23,6 +23,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.RemoteException;
@@ -161,6 +162,13 @@
      */
     public @WindowConfiguration.ActivityType int topActivityType;
 
+    /**
+     * The {@link ActivityInfo} of the top activity in this task.
+     * @hide
+     */
+    @Nullable
+    public ActivityInfo topActivityInfo;
+
     TaskInfo() {
         // Do nothing
     }
@@ -217,8 +225,11 @@
         token = IWindowContainer.Stub.asInterface(source.readStrongBinder());
         topActivityType = source.readInt();
         pictureInPictureParams = source.readInt() != 0
-            ? PictureInPictureParams.CREATOR.createFromParcel(source)
-            : null;
+                ? PictureInPictureParams.CREATOR.createFromParcel(source)
+                : null;
+        topActivityInfo = source.readInt() != 0
+                ? ActivityInfo.CREATOR.createFromParcel(source)
+                : null;
     }
 
     /**
@@ -262,6 +273,12 @@
             dest.writeInt(1);
             pictureInPictureParams.writeToParcel(dest, flags);
         }
+        if (topActivityInfo == null) {
+            dest.writeInt(0);
+        } else {
+            dest.writeInt(1);
+            topActivityInfo.writeToParcel(dest, flags);
+        }
     }
 
     @Override
@@ -278,6 +295,7 @@
                 + " resizeMode=" + resizeMode
                 + " token=" + token
                 + " topActivityType=" + topActivityType
-                + " pictureInPictureParams=" + pictureInPictureParams;
+                + " pictureInPictureParams=" + pictureInPictureParams
+                + " topActivityInfo=" + topActivityInfo;
     }
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 345eaae..1b1568a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -478,7 +478,7 @@
             try {
                 Bundle params = new Bundle();
                 ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
-                        context.getOpPackageName(), context.getFeatureId(), this, FLAG_SYSTEM,
+                        context.getOpPackageName(), context.getAttributionTag(), this, FLAG_SYSTEM,
                         params, userId);
 
                 if (pfd != null) {
@@ -1069,7 +1069,7 @@
             try {
                 Bundle outParams = new Bundle();
                 return sGlobals.mService.getWallpaperWithFeature(mContext.getOpPackageName(),
-                        mContext.getFeatureId(), null, which, outParams, userId);
+                        mContext.getAttributionTag(), null, which, outParams, userId);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             } catch (SecurityException e) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c532279..bc8d05e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5215,6 +5215,10 @@
      * <p>Because this method might take several seconds to complete, it should only be called from
      * a worker thread. This method returns {@code null} when called from the main thread.
      *
+     * <p>This method is not thread-safe, calling it from multiple threads at the same time will
+     * result in undefined behavior. If the calling thread is interrupted while the invocation is
+     * in-flight, it will eventually terminate and return {@code null}.
+     *
      * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
      * have been given to access the key and certificates associated with this alias will be
      * revoked.
@@ -6001,7 +6005,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param required Whether auto time is set required or not.
      * @throws SecurityException if {@code admin} is not a device owner.
-     * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #setAutoTime}
+     * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #setAutoTimeEnabled}
      * to turn auto time on or off and use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
      * to prevent the user from changing this setting.
      */
@@ -6019,7 +6023,7 @@
 
     /**
      * @return true if auto time is required.
-     * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #getAutoTime}
+     * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #getAutoTimeEnabled}
      */
     @Deprecated
     public boolean getAutoTimeRequired() {
@@ -6049,10 +6053,10 @@
      * @throws SecurityException if caller is not a device owner, a profile owner for the
      * primary user, or a profile owner of an organization-owned managed profile.
      */
-    public void setAutoTime(@NonNull ComponentName admin, boolean enabled) {
+    public void setAutoTimeEnabled(@NonNull ComponentName admin, boolean enabled) {
         if (mService != null) {
             try {
-                mService.setAutoTime(admin, enabled);
+                mService.setAutoTimeEnabled(admin, enabled);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -6064,10 +6068,10 @@
      * @throws SecurityException if caller is not a device owner, a profile owner for the
      * primary user, or a profile owner of an organization-owned managed profile.
      */
-    public boolean getAutoTime(@NonNull ComponentName admin) {
+    public boolean getAutoTimeEnabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getAutoTime(admin);
+                return mService.getAutoTimeEnabled(admin);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -6090,11 +6094,11 @@
      * @throws SecurityException if caller is not a device owner, a profile owner for the
      * primary user, or a profile owner of an organization-owned managed profile.
      */
-    public void setAutoTimeZone(@NonNull ComponentName admin, boolean enabled) {
+    public void setAutoTimeZoneEnabled(@NonNull ComponentName admin, boolean enabled) {
         throwIfParentInstance("setAutoTimeZone");
         if (mService != null) {
             try {
-                mService.setAutoTimeZone(admin, enabled);
+                mService.setAutoTimeZoneEnabled(admin, enabled);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -6106,11 +6110,11 @@
      * @throws SecurityException if caller is not a device owner, a profile owner for the
      * primary user, or a profile owner of an organization-owned managed profile.
      */
-    public boolean getAutoTimeZone(@NonNull ComponentName admin) {
+    public boolean getAutoTimeZoneEnabled(@NonNull ComponentName admin) {
         throwIfParentInstance("getAutoTimeZone");
         if (mService != null) {
             try {
-                return mService.getAutoTimeZone(admin);
+                return mService.getAutoTimeZoneEnabled(admin);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -8804,10 +8808,11 @@
      * <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
+     * <li>{@link android.provider.Settings.Global#AUTO_TIME} : Use {@link #setAutoTimeEnabled} 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#AUTO_TIME_ZONE} : Use
+     * {@link #setAutoTimeZoneEnabled} 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>
@@ -11847,18 +11852,19 @@
     }
 
     /**
-     * Called by Device owner to set packages as protected. User will not be able to clear app
-     * data or force-stop protected packages.
+     * Called by Device owner to disable user control over apps. User will not be able to clear
+     * app data or force-stop packages.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
-     * @param packages The package names to protect.
+     * @param packages The package names for the apps.
      * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public void setProtectedPackages(@NonNull ComponentName admin, @NonNull List<String> packages) {
-        throwIfParentInstance("setProtectedPackages");
+    public void setUserControlDisabledPackages(@NonNull ComponentName admin,
+            @NonNull List<String> packages) {
+        throwIfParentInstance("setUserControlDisabledPackages");
         if (mService != null) {
             try {
-                mService.setProtectedPackages(admin, packages);
+                mService.setUserControlDisabledPackages(admin, packages);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
@@ -11866,16 +11872,16 @@
     }
 
     /**
-     * Returns the list of packages protected by the device owner.
+     * Returns the list of packages over which user control is disabled by the device owner.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
      * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public @NonNull List<String> getProtectedPackages(@NonNull ComponentName admin) {
-        throwIfParentInstance("getProtectedPackages");
+    public @NonNull List<String> getUserControlDisabledPackages(@NonNull ComponentName admin) {
+        throwIfParentInstance("getUserControlDisabledPackages");
         if (mService != null) {
             try {
-                return mService.getProtectedPackages(admin);
+                return mService.getUserControlDisabledPackages(admin);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
@@ -11984,17 +11990,17 @@
      * must handle this intent.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with
-     * @param timeoutMs Maximum time the profile is allowed to be off in milliseconds or 0 if
+     * @param timeoutMillis Maximum time the profile is allowed to be off in milliseconds or 0 if
      *        not limited.
      * @throws IllegalStateException if the profile owner doesn't have an activity that handles
      *        {@link #ACTION_CHECK_POLICY_COMPLIANCE}
      * @see #setPersonalAppsSuspended
      */
-    public void setManagedProfileMaximumTimeOff(@NonNull ComponentName admin, long timeoutMs) {
+    public void setManagedProfileMaximumTimeOff(@NonNull ComponentName admin, long timeoutMillis) {
         throwIfParentInstance("setManagedProfileMaximumTimeOff");
         if (mService != null) {
             try {
-                mService.setManagedProfileMaximumTimeOff(admin, timeoutMs);
+                mService.setManagedProfileMaximumTimeOff(admin, timeoutMillis);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index da48663..514677e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -308,11 +308,11 @@
     void setAutoTimeRequired(in ComponentName who, boolean required);
     boolean getAutoTimeRequired();
 
-    void setAutoTime(in ComponentName who, boolean enabled);
-    boolean getAutoTime(in ComponentName who);
+    void setAutoTimeEnabled(in ComponentName who, boolean enabled);
+    boolean getAutoTimeEnabled(in ComponentName who);
 
-    void setAutoTimeZone(in ComponentName who, boolean enabled);
-    boolean getAutoTimeZone(in ComponentName who);
+    void setAutoTimeZoneEnabled(in ComponentName who, boolean enabled);
+    boolean getAutoTimeZoneEnabled(in ComponentName who);
 
     void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
     boolean getForceEphemeralUsers(in ComponentName who);
@@ -467,9 +467,9 @@
 
     boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
 
-    void setProtectedPackages(in ComponentName admin, in List<String> packages);
+    void setUserControlDisabledPackages(in ComponentName admin, in List<String> packages);
 
-    List<String> getProtectedPackages(in ComponentName admin);
+    List<String> getUserControlDisabledPackages(in ComponentName admin);
 
     void setCommonCriteriaModeEnabled(in ComponentName admin, boolean enabled);
     boolean isCommonCriteriaModeEnabled(in ComponentName admin);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index db4f1de..917eeb8 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -636,7 +636,6 @@
      * @hide
      */
     @Nullable
-    @SystemApi
     public String getDefaultSmsPackage(@UserIdInt int userId) {
         try {
             return mService.getDefaultSmsPackage(userId);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 6ae68fc..608b563 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -849,7 +849,7 @@
         synchronized (mLock) {
             if (sBluetoothLeScanner == null) {
                 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             }
         }
         return sBluetoothLeScanner;
@@ -1663,11 +1663,11 @@
         return ActivityThread.currentOpPackageName();
     }
 
-    private String getFeatureId() {
+    private String getAttributionTag() {
         // Workaround for legacy API for getting a BluetoothAdapter not
         // passing a context
         if (mContext != null) {
-            return mContext.getFeatureId();
+            return mContext.getAttributionTag();
         }
         return null;
     }
@@ -1709,7 +1709,7 @@
         try {
             mServiceLock.readLock().lock();
             if (mService != null) {
-                return mService.startDiscovery(getOpPackageName(), getFeatureId());
+                return mService.startDiscovery(getOpPackageName(), getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 7ff6466..3b4fe0a 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -62,7 +62,7 @@
      * @hide
      */
     public BluetoothManager(Context context) {
-        if (context.getFeatureId() == null) {
+        if (context.getAttributionTag() == null) {
             context = context.getApplicationContext();
             if (context == null) {
                 throw new IllegalArgumentException(
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index bd3298c7..d8e8b27 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -230,12 +230,12 @@
         }
 
         @Override
-        public Cursor query(String callingPkg, @Nullable String featureId, Uri uri,
+        public Cursor query(String callingPkg, @Nullable String attributionTag, Uri uri,
                 @Nullable String[] projection, @Nullable Bundle queryArgs,
                 @Nullable ICancellationSignal cancellationSignal) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, featureId, uri, null)
+            if (enforceReadPermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 // The caller has no access to the data, so return an empty cursor with
                 // the columns in the requested order. The caller may ask for an invalid
@@ -253,7 +253,7 @@
                 // columns. We then use the column names to return an empty cursor.
                 Cursor cursor;
                 final Pair<String, String> original = setCallingPackage(
-                        new Pair<>(callingPkg, featureId));
+                        new Pair<>(callingPkg, attributionTag));
                 try {
                     cursor = mInterface.query(
                             uri, projection, queryArgs,
@@ -272,7 +272,7 @@
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "query");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.query(
                         uri, projection, queryArgs,
@@ -308,15 +308,15 @@
         }
 
         @Override
-        public Uri insert(String callingPkg, @Nullable String featureId, Uri uri,
+        public Uri insert(String callingPkg, @Nullable String attributionTag, Uri uri,
                 ContentValues initialValues, Bundle extras) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, featureId, uri, null)
+            if (enforceWritePermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 final Pair<String, String> original = setCallingPackage(
-                        new Pair<>(callingPkg, featureId));
+                        new Pair<>(callingPkg, attributionTag));
                 try {
                     return rejectInsert(uri, initialValues);
                 } finally {
@@ -325,7 +325,7 @@
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return maybeAddUserId(mInterface.insert(uri, initialValues, extras), userId);
             } catch (RemoteException e) {
@@ -337,17 +337,17 @@
         }
 
         @Override
-        public int bulkInsert(String callingPkg, @Nullable String featureId, Uri uri,
+        public int bulkInsert(String callingPkg, @Nullable String attributionTag, Uri uri,
                 ContentValues[] initialValues) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, featureId, uri, null)
+            if (enforceWritePermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.bulkInsert(uri, initialValues);
             } catch (RemoteException e) {
@@ -359,8 +359,9 @@
         }
 
         @Override
-        public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
-                String authority, ArrayList<ContentProviderOperation> operations)
+        public ContentProviderResult[] applyBatch(String callingPkg,
+                @Nullable String attributionTag, String authority,
+                ArrayList<ContentProviderOperation> operations)
                 throws OperationApplicationException {
             validateIncomingAuthority(authority);
             int numOperations = operations.size();
@@ -377,13 +378,13 @@
                     operations.set(i, operation);
                 }
                 if (operation.isReadOperation()) {
-                    if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    if (enforceReadPermission(callingPkg, attributionTag, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
                 if (operation.isWriteOperation()) {
-                    if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    if (enforceWritePermission(callingPkg, attributionTag, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
@@ -391,7 +392,7 @@
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 ContentProviderResult[] results = mInterface.applyBatch(authority,
                         operations);
@@ -413,16 +414,17 @@
         }
 
         @Override
-        public int delete(String callingPkg, @Nullable String featureId, Uri uri, Bundle extras) {
+        public int delete(String callingPkg, @Nullable String attributionTag, Uri uri,
+                Bundle extras) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, featureId, uri, null)
+            if (enforceWritePermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.delete(uri, extras);
             } catch (RemoteException e) {
@@ -434,17 +436,17 @@
         }
 
         @Override
-        public int update(String callingPkg, @Nullable String featureId, Uri uri,
+        public int update(String callingPkg, @Nullable String attributionTag, Uri uri,
                 ContentValues values, Bundle extras) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, featureId, uri, null)
+            if (enforceWritePermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "update");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.update(uri, values, extras);
             } catch (RemoteException e) {
@@ -456,15 +458,15 @@
         }
 
         @Override
-        public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId,
+        public ParcelFileDescriptor openFile(String callingPkg, @Nullable String attributionTag,
                 Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken)
                 throws FileNotFoundException {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, featureId, uri, mode, callerToken);
+            enforceFilePermission(callingPkg, attributionTag, uri, mode, callerToken);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.openFile(
                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -477,15 +479,15 @@
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+        public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String attributionTag,
                 Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, featureId, uri, mode, null);
+            enforceFilePermission(callingPkg, attributionTag, uri, mode, null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.openAssetFile(
                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -498,13 +500,13 @@
         }
 
         @Override
-        public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+        public Bundle call(String callingPkg, @Nullable String attributionTag, String authority,
                 String method, @Nullable String arg, @Nullable Bundle extras) {
             validateIncomingAuthority(authority);
             Bundle.setDefusable(extras, true);
             Trace.traceBegin(TRACE_TAG_DATABASE, "call");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.call(authority, method, arg, extras);
             } catch (RemoteException e) {
@@ -532,15 +534,15 @@
 
         @Override
         public AssetFileDescriptor openTypedAssetFile(String callingPkg,
-                @Nullable String featureId, Uri uri, String mimeType, Bundle opts,
+                @Nullable String attributionTag, Uri uri, String mimeType, Bundle opts,
                 ICancellationSignal cancellationSignal) throws FileNotFoundException {
             Bundle.setDefusable(opts, true);
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, featureId, uri, "r", null);
+            enforceFilePermission(callingPkg, attributionTag, uri, "r", null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.openTypedAssetFile(
                         uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
@@ -558,17 +560,17 @@
         }
 
         @Override
-        public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
+        public Uri canonicalize(String callingPkg, @Nullable String attributionTag, Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, featureId, uri, null)
+            if (enforceReadPermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return maybeAddUserId(mInterface.canonicalize(uri), userId);
             } catch (RemoteException e) {
@@ -580,26 +582,26 @@
         }
 
         @Override
-        public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+        public void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
                 RemoteCallback callback) {
             final Bundle result = new Bundle();
             result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
-                    canonicalize(callingPkg, featureId, uri));
+                    canonicalize(callingPkg, attributionTag, uri));
             callback.sendResult(result);
         }
 
         @Override
-        public Uri uncanonicalize(String callingPkg, String featureId,  Uri uri) {
+        public Uri uncanonicalize(String callingPkg, String attributionTag,  Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, featureId, uri, null)
+            if (enforceReadPermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return maybeAddUserId(mInterface.uncanonicalize(uri), userId);
             } catch (RemoteException e) {
@@ -611,17 +613,17 @@
         }
 
         @Override
-        public boolean refresh(String callingPkg, String featureId, Uri uri, Bundle extras,
+        public boolean refresh(String callingPkg, String attributionTag, Uri uri, Bundle extras,
                 ICancellationSignal cancellationSignal) throws RemoteException {
             uri = validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, featureId, uri, null)
+            if (enforceReadPermission(callingPkg, attributionTag, uri, null)
                     != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.refresh(uri, extras,
                         CancellationSignal.fromTransport(cancellationSignal));
@@ -632,13 +634,13 @@
         }
 
         @Override
-        public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+        public int checkUriPermission(String callingPkg, @Nullable String attributionTag, Uri uri,
                 int uid, int modeFlags) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
             final Pair<String, String> original = setCallingPackage(
-                    new Pair<>(callingPkg, featureId));
+                    new Pair<>(callingPkg, attributionTag));
             try {
                 return mInterface.checkUriPermission(uri, uid, modeFlags);
             } catch (RemoteException e) {
@@ -649,47 +651,50 @@
             }
         }
 
-        private void enforceFilePermission(String callingPkg, @Nullable String featureId, Uri uri,
-                String mode, IBinder callerToken) throws FileNotFoundException, SecurityException {
+        private void enforceFilePermission(String callingPkg, @Nullable String attributionTag,
+                Uri uri, String mode, IBinder callerToken)
+                throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
-                if (enforceWritePermission(callingPkg, featureId, uri, callerToken)
+                if (enforceWritePermission(callingPkg, attributionTag, uri, callerToken)
                         != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             } else {
-                if (enforceReadPermission(callingPkg, featureId, uri, callerToken)
+                if (enforceReadPermission(callingPkg, attributionTag, uri, callerToken)
                         != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             }
         }
 
-        private int enforceReadPermission(String callingPkg, @Nullable String featureId, Uri uri,
-                IBinder callerToken)
+        private int enforceReadPermission(String callingPkg, @Nullable String attributionTag,
+                Uri uri, IBinder callerToken)
                 throws SecurityException {
-            final int mode = enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
+            final int mode = enforceReadPermissionInner(uri, callingPkg, attributionTag,
+                    callerToken);
             if (mode != MODE_ALLOWED) {
                 return mode;
             }
 
-            return noteProxyOp(callingPkg, featureId, mReadOp);
+            return noteProxyOp(callingPkg, attributionTag, mReadOp);
         }
 
-        private int enforceWritePermission(String callingPkg, String featureId, Uri uri,
+        private int enforceWritePermission(String callingPkg, String attributionTag, Uri uri,
                 IBinder callerToken)
                 throws SecurityException {
-            final int mode = enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
+            final int mode = enforceWritePermissionInner(uri, callingPkg, attributionTag,
+                    callerToken);
             if (mode != MODE_ALLOWED) {
                 return mode;
             }
 
-            return noteProxyOp(callingPkg, featureId, mWriteOp);
+            return noteProxyOp(callingPkg, attributionTag, mWriteOp);
         }
 
-        private int noteProxyOp(String callingPkg, String featureId, int op) {
+        private int noteProxyOp(String callingPkg, String attributionTag, int op) {
             if (op != AppOpsManager.OP_NONE) {
                 int mode = mAppOpsManager.noteProxyOp(op, callingPkg, Binder.getCallingUid(),
-                        featureId, null);
+                        attributionTag, null);
                 return mode == MODE_DEFAULT ? MODE_IGNORED : mode;
             }
 
@@ -711,19 +716,19 @@
      * associated with that permission.
      */
     private int checkPermissionAndAppOp(String permission, String callingPkg,
-            @Nullable String featureId, IBinder callerToken) {
+            @Nullable String attributionTag, IBinder callerToken) {
         if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
                 callerToken) != PERMISSION_GRANTED) {
             return MODE_ERRORED;
         }
 
-        return mTransport.noteProxyOp(callingPkg, featureId,
+        return mTransport.noteProxyOp(callingPkg, attributionTag,
                 AppOpsManager.permissionToOpCode(permission));
     }
 
     /** {@hide} */
     protected int enforceReadPermissionInner(Uri uri, String callingPkg,
-            @Nullable String featureId, IBinder callerToken) throws SecurityException {
+            @Nullable String attributionTag, IBinder callerToken) throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -737,7 +742,7 @@
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getReadPermission();
             if (componentPerm != null) {
-                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
+                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, attributionTag,
                         callerToken);
                 if (mode == MODE_ALLOWED) {
                     return MODE_ALLOWED;
@@ -757,8 +762,8 @@
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getReadPermission();
                     if (pathPerm != null && pp.match(path)) {
-                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
-                                callerToken);
+                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg,
+                                attributionTag, callerToken);
                         if (mode == MODE_ALLOWED) {
                             return MODE_ALLOWED;
                         } else {
@@ -807,7 +812,7 @@
 
     /** {@hide} */
     protected int enforceWritePermissionInner(Uri uri, String callingPkg,
-            @Nullable String featureId, IBinder callerToken) throws SecurityException {
+            @Nullable String attributionTag, IBinder callerToken) throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -821,8 +826,8 @@
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getWritePermission();
             if (componentPerm != null) {
-                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
-                        callerToken);
+                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg,
+                        attributionTag, callerToken);
                 if (mode == MODE_ALLOWED) {
                     return MODE_ALLOWED;
                 } else {
@@ -841,8 +846,8 @@
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getWritePermission();
                     if (pathPerm != null && pp.match(path)) {
-                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
-                                callerToken);
+                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg,
+                                attributionTag, callerToken);
                         if (mode == MODE_ALLOWED) {
                             return MODE_ALLOWED;
                         } else {
@@ -943,16 +948,16 @@
     }
 
     /**
-     * Return the feature in the package of the caller that initiated the request being
+     * Return the attribution tag of the caller that initiated the request being
      * processed on the current thread. Returns {@code null} if not currently processing
-     * a request of the request is for the default feature.
+     * a request of the request is for the default attribution.
      * <p>
      * This will always return {@code null} when processing
      * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
      *
      * @see #getCallingPackage
      */
-    public final @Nullable String getCallingFeatureId() {
+    public final @Nullable String getCallingAttributionTag() {
         final Pair<String, String> pkg = mCallingPackage.get();
         if (pkg != null) {
             return pkg.second;
@@ -962,6 +967,14 @@
     }
 
     /**
+     * @removed
+     */
+    @Deprecated
+    public final @Nullable String getCallingFeatureId() {
+        return getCallingAttributionTag();
+    }
+
+    /**
      * Return the package name of the caller that initiated the request being
      * processed on the current thread. The returned package will have
      * <em>not</em> been verified to belong to the calling UID. Returns
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index a9b7862..d0f5ec4 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -80,7 +80,7 @@
     private final IContentProvider mContentProvider;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mPackageName;
-    private final @Nullable String mFeatureId;
+    private final @Nullable String mAttributionTag;
     private final String mAuthority;
     private final boolean mStable;
 
@@ -104,7 +104,7 @@
         mContentResolver = contentResolver;
         mContentProvider = contentProvider;
         mPackageName = contentResolver.mPackageName;
-        mFeatureId = contentResolver.mFeatureId;
+        mAttributionTag = contentResolver.mAttributionTag;
 
         mAuthority = authority;
         mStable = stable;
@@ -195,7 +195,8 @@
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
             final Cursor cursor = mContentProvider.query(
-                    mPackageName, mFeatureId, uri, projection, queryArgs, remoteCancellationSignal);
+                    mPackageName, mAttributionTag, uri, projection, queryArgs,
+                    remoteCancellationSignal);
             if (cursor == null) {
                 return null;
             }
@@ -255,7 +256,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.canonicalize(mPackageName, mFeatureId, url);
+            return mContentProvider.canonicalize(mPackageName, mAttributionTag, url);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -273,7 +274,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.uncanonicalize(mPackageName, mFeatureId, url);
+            return mContentProvider.uncanonicalize(mPackageName, mAttributionTag, url);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -298,7 +299,7 @@
                 remoteCancellationSignal = mContentProvider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return mContentProvider.refresh(mPackageName, mFeatureId, url, extras,
+            return mContentProvider.refresh(mPackageName, mAttributionTag, url, extras,
                     remoteCancellationSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
@@ -318,7 +319,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.checkUriPermission(mPackageName, mFeatureId, uri, uid,
+            return mContentProvider.checkUriPermission(mPackageName, mAttributionTag, uri, uid,
                     modeFlags);
         } catch (DeadObjectException e) {
             if (!mStable) {
@@ -344,7 +345,8 @@
 
         beforeRemote();
         try {
-            return mContentProvider.insert(mPackageName, mFeatureId, url, initialValues, extras);
+            return mContentProvider.insert(mPackageName, mAttributionTag, url, initialValues,
+                    extras);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -364,7 +366,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.bulkInsert(mPackageName, mFeatureId, url, initialValues);
+            return mContentProvider.bulkInsert(mPackageName, mAttributionTag, url, initialValues);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -388,7 +390,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.delete(mPackageName, mFeatureId, url, extras);
+            return mContentProvider.delete(mPackageName, mAttributionTag, url, extras);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -413,7 +415,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.update(mPackageName, mFeatureId, url, values, extras);
+            return mContentProvider.update(mPackageName, mAttributionTag, url, values, extras);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -457,8 +459,8 @@
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openFile(mPackageName, mFeatureId, url, mode, remoteSignal,
-                    null);
+            return mContentProvider.openFile(mPackageName, mAttributionTag, url, mode,
+                    remoteSignal, null);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -502,7 +504,7 @@
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openAssetFile(mPackageName, mFeatureId, url, mode,
+            return mContentProvider.openAssetFile(mPackageName, mAttributionTag, url, mode,
                     remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
@@ -544,7 +546,7 @@
                 signal.setRemote(remoteSignal);
             }
             return mContentProvider.openTypedAssetFile(
-                    mPackageName, mFeatureId, uri, mimeTypeFilter, opts, remoteSignal);
+                    mPackageName, mAttributionTag, uri, mimeTypeFilter, opts, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -571,7 +573,8 @@
 
         beforeRemote();
         try {
-            return mContentProvider.applyBatch(mPackageName, mFeatureId, authority, operations);
+            return mContentProvider.applyBatch(mPackageName, mAttributionTag, authority,
+                    operations);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -597,7 +600,8 @@
 
         beforeRemote();
         try {
-            return mContentProvider.call(mPackageName, mFeatureId, authority, method, arg, extras);
+            return mContentProvider.call(mPackageName, mAttributionTag, authority, method, arg,
+                    extras);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 31e1fc8..b134c37 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -767,7 +767,7 @@
     public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
         mContext = context != null ? context : ActivityThread.currentApplication();
         mPackageName = mContext.getOpPackageName();
-        mFeatureId = mContext.getFeatureId();
+        mAttributionTag = mContext.getAttributionTag();
         mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
         mWrapped = wrapped;
     }
@@ -1144,7 +1144,7 @@
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
             try {
-                qCursor = unstableProvider.query(mPackageName, mFeatureId, uri, projection,
+                qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,
                         queryArgs, remoteCancellationSignal);
             } catch (DeadObjectException e) {
                 // The remote process has died...  but we only hold an unstable
@@ -1155,7 +1155,7 @@
                 if (stableProvider == null) {
                     return null;
                 }
-                qCursor = stableProvider.query(mPackageName, mFeatureId, uri, projection,
+                qCursor = stableProvider.query(mPackageName, mAttributionTag, uri, projection,
                         queryArgs, remoteCancellationSignal);
             }
             if (qCursor == null) {
@@ -1247,7 +1247,7 @@
 
         try {
             final UriResultListener resultListener = new UriResultListener();
-            provider.canonicalizeAsync(mPackageName, mFeatureId, url,
+            provider.canonicalizeAsync(mPackageName, mAttributionTag, url,
                     new RemoteCallback(resultListener));
             resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
             return resultListener.result;
@@ -1294,7 +1294,7 @@
         }
 
         try {
-            return provider.uncanonicalize(mPackageName, mFeatureId, url);
+            return provider.uncanonicalize(mPackageName, mAttributionTag, url);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1346,7 +1346,7 @@
                 remoteCancellationSignal = provider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return provider.refresh(mPackageName, mFeatureId, url, extras,
+            return provider.refresh(mPackageName, mAttributionTag, url, extras,
                     remoteCancellationSignal);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
@@ -1748,7 +1748,8 @@
 
                     try {
                         fd = unstableProvider.openAssetFile(
-                                mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
+                                mPackageName, mAttributionTag, uri, mode,
+                                remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -1763,7 +1764,7 @@
                             throw new FileNotFoundException("No content provider: " + uri);
                         }
                         fd = stableProvider.openAssetFile(
-                                mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
+                                mPackageName, mAttributionTag, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -1914,7 +1915,8 @@
 
             try {
                 fd = unstableProvider.openTypedAssetFile(
-                        mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
+                        mPackageName, mAttributionTag, uri, mimeType, opts,
+                        remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -1929,7 +1931,8 @@
                     throw new FileNotFoundException("No content provider: " + uri);
                 }
                 fd = stableProvider.openTypedAssetFile(
-                        mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
+                        mPackageName, mAttributionTag, uri, mimeType, opts,
+                        remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -2077,7 +2080,7 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            Uri createdRow = provider.insert(mPackageName, mFeatureId, url, values, extras);
+            Uri createdRow = provider.insert(mPackageName, mAttributionTag, url, values, extras);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
             return createdRow;
@@ -2158,7 +2161,7 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsCreated = provider.bulkInsert(mPackageName, mFeatureId, url, values);
+            int rowsCreated = provider.bulkInsert(mPackageName, mAttributionTag, url, values);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
             return rowsCreated;
@@ -2217,7 +2220,7 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsDeleted = provider.delete(mPackageName, mFeatureId, url, extras);
+            int rowsDeleted = provider.delete(mPackageName, mAttributionTag, url, extras);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "delete", null);
             return rowsDeleted;
@@ -2284,7 +2287,7 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsUpdated = provider.update(mPackageName, mFeatureId, uri, values, extras);
+            int rowsUpdated = provider.update(mPackageName, mAttributionTag, uri, values, extras);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, uri, "update", null);
             return rowsUpdated;
@@ -2333,7 +2336,7 @@
             throw new IllegalArgumentException("Unknown authority " + authority);
         }
         try {
-            final Bundle res = provider.call(mPackageName, mFeatureId, authority, method, arg,
+            final Bundle res = provider.call(mPackageName, mAttributionTag, authority, method, arg,
                     extras);
             Bundle.setDefusable(res, true);
             return res;
@@ -3746,8 +3749,8 @@
     }
 
     /** @hide */
-    public @Nullable String getFeatureId() {
-        return mFeatureId;
+    public @Nullable String getAttributionTag() {
+        return mAttributionTag;
     }
 
     @UnsupportedAppUsage
@@ -3757,7 +3760,7 @@
 
     @UnsupportedAppUsage
     final String mPackageName;
-    final @Nullable String mFeatureId;
+    final @Nullable String mAttributionTag;
     final int mTargetSdkVersion;
     final ContentInterface mWrapped;
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5e9ed60..318ae11 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -815,16 +815,25 @@
     }
 
     /**
-     * <p>Features are used in complex apps to logically separate parts of the app. E.g. a
-     * blogging app might also have a instant messaging app built in.
+     * <p>Attribution can be used in complex apps to logically separate parts of the app. E.g. a
+     * blogging app might also have a instant messaging app built in. In this case two separate tags
+     * can for used each sub-feature.
      *
-     * @return the feature id this context is for or {@code null} if this is the default
-     * feature.
+     * @return the attribution tag this context is for or {@code null} if this is the default.
      */
-    public @Nullable String getFeatureId() {
+    public @Nullable String getAttributionTag() {
         return null;
     }
 
+    // TODO moltmann: Remove
+    /**
+     * @removed
+     */
+    @Deprecated
+    public @Nullable String getFeatureId() {
+        return getAttributionTag();
+    }
+
     /** Return the full application info for this context's package. */
     public abstract ApplicationInfo getApplicationInfo();
 
@@ -5826,19 +5835,29 @@
     }
 
     /**
-     * Return a new Context object for the current Context but for a different feature in the app.
-     * Features can be used by complex apps to separate logical parts.
+     * Return a new Context object for the current Context but attribute to a different tag.
+     * In complex apps attribution tagging can be used to distinguish between separate logical
+     * parts.
      *
-     * @param featureId The feature id or {@code null} to create a context for the default feature.
+     * @param attributionTag The tag or {@code null} to create a context for the default.
      *
-     * @return A {@link Context} for the feature
+     * @return A {@link Context} that is tagged for the new attribution
      *
-     * @see #getFeatureId()
+     * @see #getAttributionTag()
      */
-    public @NonNull Context createFeatureContext(@Nullable String featureId) {
+    public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
+    // TODO moltmann: remove
+    /**
+     * @removed
+     */
+    @Deprecated
+    public @NonNull Context createFeatureContext(@Nullable String featureId) {
+        return createAttributionContext(featureId);
+    }
+
     /**
      * Return a new Context object for the current Context but whose storage
      * APIs are backed by device-protected storage.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b7e04cf..d389d2a 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -164,8 +164,8 @@
 
     /** @hide */
     @Override
-    public @Nullable String getFeatureId() {
-        return mBase.getFeatureId();
+    public @Nullable String getAttributionTag() {
+        return mBase.getAttributionTag();
     }
 
     @Override
@@ -984,8 +984,8 @@
     }
 
     @Override
-    public @NonNull Context createFeatureContext(@Nullable String featureId) {
-        return mBase.createFeatureContext(featureId);
+    public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
+        return mBase.createAttributionContext(attributionTag);
     }
 
     @Override
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 37643da..84b0f0e 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -38,7 +38,7 @@
  * @hide
  */
 public interface IContentProvider extends IInterface {
-    public Cursor query(String callingPkg, @Nullable String featureId, Uri url,
+    public Cursor query(String callingPkg, @Nullable String attributionTag, Uri url,
             @Nullable String[] projection,
             @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
             throws RemoteException;
@@ -59,8 +59,8 @@
             throws RemoteException {
         return insert(callingPkg, null, url, initialValues, null);
     }
-    public Uri insert(String callingPkg, String featureId, Uri url, ContentValues initialValues,
-            Bundle extras) throws RemoteException;
+    public Uri insert(String callingPkg, String attributionTag, Uri url,
+            ContentValues initialValues, Bundle extras) throws RemoteException;
     @Deprecated
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
             + "ContentProviderClient#bulkInsert(android.net.Uri, android.content.ContentValues[])"
@@ -69,7 +69,7 @@
             throws RemoteException {
         return bulkInsert(callingPkg, null, url, initialValues);
     }
-    public int bulkInsert(String callingPkg, String featureId, Uri url,
+    public int bulkInsert(String callingPkg, String attributionTag, Uri url,
             ContentValues[] initialValues) throws RemoteException;
     @Deprecated
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
@@ -80,7 +80,7 @@
         return delete(callingPkg, null, url,
                 ContentResolver.createSqlQueryBundle(selection, selectionArgs));
     }
-    public int delete(String callingPkg, String featureId, Uri url, Bundle extras)
+    public int delete(String callingPkg, String attributionTag, Uri url, Bundle extras)
             throws RemoteException;
     @Deprecated
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
@@ -91,18 +91,18 @@
         return update(callingPkg, null, url, values,
                 ContentResolver.createSqlQueryBundle(selection, selectionArgs));
     }
-    public int update(String callingPkg, String featureId, Uri url, ContentValues values,
+    public int update(String callingPkg, String attributionTag, Uri url, ContentValues values,
             Bundle extras) throws RemoteException;
 
-    public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId, Uri url,
-            String mode, ICancellationSignal signal, IBinder callerToken)
+    public ParcelFileDescriptor openFile(String callingPkg, @Nullable String attributionTag,
+            Uri url, String mode, ICancellationSignal signal, IBinder callerToken)
             throws RemoteException, FileNotFoundException;
 
-    public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+    public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String attributionTag,
             Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException;
 
-    public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+    public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String attributionTag,
             String authority, ArrayList<ContentProviderOperation> operations)
             throws RemoteException, OperationApplicationException;
 
@@ -115,15 +115,15 @@
         return call(callingPkg, null, "unknown", method, arg, extras);
     }
 
-    public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+    public Bundle call(String callingPkg, @Nullable String attributionTag, String authority,
             String method, @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
 
-    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
-            int modeFlags) throws RemoteException;
+    public int checkUriPermission(String callingPkg, @Nullable String attributionTag, Uri uri,
+            int uid, int modeFlags) throws RemoteException;
 
     public ICancellationSignal createCancellationSignal() throws RemoteException;
 
-    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+    public Uri canonicalize(String callingPkg, @Nullable String attributionTag, Uri uri)
             throws RemoteException;
 
     /**
@@ -131,20 +131,21 @@
      * call returns immediately, and the resulting type is returned when available via
      * a binder callback.
      */
-    void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+    void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
             RemoteCallback callback) throws RemoteException;
 
-    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+    public Uri uncanonicalize(String callingPkg, @Nullable String attributionTag, Uri uri)
             throws RemoteException;
 
-    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+    public boolean refresh(String callingPkg, @Nullable String attributionTag, Uri url,
             @Nullable Bundle extras, ICancellationSignal cancellationSignal) throws RemoteException;
 
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
 
-    public AssetFileDescriptor openTypedAssetFile(String callingPkg, @Nullable String featureId,
-            Uri url, String mimeType, Bundle opts, ICancellationSignal signal)
+    public AssetFileDescriptor openTypedAssetFile(String callingPkg,
+            @Nullable String attributionTag, Uri url, String mimeType, Bundle opts,
+            ICancellationSignal signal)
             throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index 33bd839..b434072 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -123,7 +123,7 @@
      * @param uid The uid for which to check.
      * @param packageName The package name for which to check. If null the
      *     the first package for the calling UID will be used.
-     * @param featureId Feature in the package
+     * @param attributionTag attribution tag
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
      * @param message A message describing the reason the permission was checked
@@ -133,9 +133,9 @@
     @PermissionResult
     public static int checkPermissionForDataDelivery(@NonNull Context context,
             @NonNull String permission, int pid, int uid, @Nullable String packageName,
-            @Nullable String featureId, @Nullable String message) {
-        return checkPermissionCommon(context, permission, pid, uid, packageName, featureId, message,
-                true /*forDataDelivery*/);
+            @Nullable String attributionTag, @Nullable String message) {
+        return checkPermissionCommon(context, permission, pid, uid, packageName, attributionTag,
+                message, true /*forDataDelivery*/);
     }
 
     /**
@@ -171,8 +171,8 @@
     @PermissionResult
     public static int checkPermissionForPreflight(@NonNull Context context,
             @NonNull String permission, int pid, int uid, @Nullable String packageName) {
-        return checkPermissionCommon(context, permission, pid, uid, packageName, null /*featureId*/,
-                null /*message*/, false /*forDataDelivery*/);
+        return checkPermissionCommon(context, permission, pid, uid, packageName,
+                null /*attributionTag*/, null /*message*/, false /*forDataDelivery*/);
     }
 
     /**
@@ -207,7 +207,7 @@
     public static int checkSelfPermissionForDataDelivery(@NonNull Context context,
             @NonNull String permission, @Nullable String message) {
         return checkPermissionForDataDelivery(context, permission, Process.myPid(),
-                Process.myUid(), context.getPackageName(), context.getFeatureId(), message);
+                Process.myUid(), context.getPackageName(), context.getAttributionTag(), message);
     }
 
     /**
@@ -266,7 +266,7 @@
      * @param permission The permission to check.
      * @param packageName The package name making the IPC. If null the
      *     the first package for the calling UID will be used.
-     * @param featureId The feature inside of the app
+     * @param attributionTag attribution tag
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
      * @param message A message describing the reason the permission was checked
@@ -276,12 +276,12 @@
     @PermissionResult
     public static int checkCallingPermissionForDataDelivery(@NonNull Context context,
             @NonNull String permission, @Nullable String packageName,
-            @Nullable String featureId, @Nullable String message) {
+            @Nullable String attributionTag, @Nullable String message) {
         if (Binder.getCallingPid() == Process.myPid()) {
             return PERMISSION_HARD_DENIED;
         }
         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
-                Binder.getCallingUid(), packageName, featureId, message);
+                Binder.getCallingUid(), packageName, attributionTag, message);
     }
 
     /**
@@ -343,20 +343,20 @@
      * @param permission The permission to check.
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
-     * @param featureId feature Id of caller (if not self)
+     * @param attributionTag attribution tag of caller (if not self)
      * @param message A message describing the reason the permission was checked
      *
      * @see #checkCallingOrSelfPermissionForPreflight(Context, String)
      */
     @PermissionResult
     public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context,
-            @NonNull String permission, @Nullable String featureId, @Nullable String message) {
+            @NonNull String permission, @Nullable String attributionTag, @Nullable String message) {
         String packageName = (Binder.getCallingPid() == Process.myPid())
                 ? context.getPackageName() : null;
-        featureId = (Binder.getCallingPid() == Process.myPid())
-                ? context.getFeatureId() : featureId;
+        attributionTag = (Binder.getCallingPid() == Process.myPid())
+                ? context.getAttributionTag() : attributionTag;
         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
-                Binder.getCallingUid(), packageName, featureId, message);
+                Binder.getCallingUid(), packageName, attributionTag, message);
     }
 
     /**
@@ -395,7 +395,7 @@
     }
 
     static int checkPermissionCommon(@NonNull Context context, @NonNull String permission,
-            int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+            int pid, int uid, @Nullable String packageName, @Nullable String attributionTag,
             @Nullable String message, boolean forDataDelivery) {
         final PermissionInfo permissionInfo;
         try {
@@ -414,18 +414,18 @@
         }
 
         if (permissionInfo.isAppOp()) {
-            return checkAppOpPermission(context, permission, pid, uid, packageName, featureId,
+            return checkAppOpPermission(context, permission, pid, uid, packageName, attributionTag,
                     message, forDataDelivery);
         }
         if (permissionInfo.isRuntime()) {
-            return checkRuntimePermission(context, permission, pid, uid, packageName, featureId,
-                    message, forDataDelivery);
+            return checkRuntimePermission(context, permission, pid, uid, packageName,
+                    attributionTag, message, forDataDelivery);
         }
         return context.checkPermission(permission, pid, uid);
     }
 
     private static int checkAppOpPermission(@NonNull Context context, @NonNull String permission,
-            int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+            int pid, int uid, @Nullable String packageName, @Nullable String attributionTag,
             @Nullable String message, boolean forDataDelivery) {
         final String op = AppOpsManager.permissionToOp(permission);
         if (op == null || packageName == null) {
@@ -434,11 +434,12 @@
 
         final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
         final int opMode = (forDataDelivery)
-                ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message)
-                : appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName);
+                ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, attributionTag, message)
+                : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName);
 
         switch (opMode) {
-            case AppOpsManager.MODE_ALLOWED: {
+            case AppOpsManager.MODE_ALLOWED:
+            case AppOpsManager.MODE_FOREGROUND: {
                 return PERMISSION_GRANTED;
             }
             case AppOpsManager.MODE_DEFAULT: {
@@ -453,7 +454,7 @@
     }
 
     private static int checkRuntimePermission(@NonNull Context context, @NonNull String permission,
-            int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+            int pid, int uid, @Nullable String packageName, @Nullable String attributionTag,
             @Nullable String message, boolean forDataDelivery) {
         if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
             return PERMISSION_HARD_DENIED;
@@ -466,13 +467,15 @@
 
         final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
         final int opMode = (forDataDelivery)
-                ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message)
-                : appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName);
+                ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, attributionTag, message)
+                : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName);
 
-        if (opMode == AppOpsManager.MODE_ALLOWED) {
-            return PERMISSION_GRANTED;
-        } else {
-            return PERMISSION_SOFT_DENIED;
+        switch (opMode) {
+            case AppOpsManager.MODE_ALLOWED:
+            case AppOpsManager.MODE_FOREGROUND:
+                return PERMISSION_GRANTED;
+            default:
+                return PERMISSION_SOFT_DENIED;
         }
     }
 }
diff --git a/core/java/android/content/integrity/AppIntegrityManager.java b/core/java/android/content/integrity/AppIntegrityManager.java
index 9f95d4d..2869abb 100644
--- a/core/java/android/content/integrity/AppIntegrityManager.java
+++ b/core/java/android/content/integrity/AppIntegrityManager.java
@@ -25,6 +25,8 @@
 import android.content.pm.ParceledListSlice;
 import android.os.RemoteException;
 
+import java.util.List;
+
 /**
  * Class for pushing rules used to check the integrity of app installs.
  *
@@ -121,4 +123,21 @@
             throw e.rethrowAsRuntimeException();
         }
     }
+
+    /**
+     * Get the package names of all whitelisted rule providers.
+     *
+     * <p>Warning: this method is only used for tests.
+     *
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public List<String> getWhitelistedRuleProviders() {
+        try {
+            return mManager.getWhitelistedRuleProviders();
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
 }
diff --git a/core/java/android/content/integrity/IAppIntegrityManager.aidl b/core/java/android/content/integrity/IAppIntegrityManager.aidl
index 4714ad7..94197bb 100644
--- a/core/java/android/content/integrity/IAppIntegrityManager.aidl
+++ b/core/java/android/content/integrity/IAppIntegrityManager.aidl
@@ -19,6 +19,7 @@
 import android.content.integrity.Rule;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
+import java.util.List;
 
 /** @hide */
 interface IAppIntegrityManager {
@@ -26,4 +27,5 @@
     String getCurrentRuleSetVersion();
     String getCurrentRuleSetProvider();
     ParceledListSlice<Rule> getCurrentRules();
+    List<String> getWhitelistedRuleProviders();
 }
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0b2b5b1..f25ce76 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1222,13 +1222,7 @@
         dest.writeInt(lockTaskLaunchMode);
         if (windowLayout != null) {
             dest.writeInt(1);
-            dest.writeInt(windowLayout.width);
-            dest.writeFloat(windowLayout.widthFraction);
-            dest.writeInt(windowLayout.height);
-            dest.writeFloat(windowLayout.heightFraction);
-            dest.writeInt(windowLayout.gravity);
-            dest.writeInt(windowLayout.minWidth);
-            dest.writeInt(windowLayout.minHeight);
+            windowLayout.writeToParcel(dest);
         } else {
             dest.writeInt(0);
         }
@@ -1372,8 +1366,8 @@
      * @attr ref android.R.styleable#AndroidManifestLayout_minHeight
      */
     public static final class WindowLayout {
-        public WindowLayout(int width, float widthFraction, int height, float heightFraction, int gravity,
-                int minWidth, int minHeight) {
+        public WindowLayout(int width, float widthFraction, int height, float heightFraction,
+                int gravity, int minWidth, int minHeight) {
             this.width = width;
             this.widthFraction = widthFraction;
             this.height = height;
@@ -1392,6 +1386,7 @@
             gravity = source.readInt();
             minWidth = source.readInt();
             minHeight = source.readInt();
+            windowLayoutAffinity = source.readString();
         }
 
         /**
@@ -1458,11 +1453,30 @@
         public final int minHeight;
 
         /**
+         * Affinity of window layout parameters. Activities with the same UID and window layout
+         * affinity will share the same window dimension record.
+         * @hide
+         */
+        public String windowLayoutAffinity;
+
+        /**
          * Returns if this {@link WindowLayout} has specified bounds.
          * @hide
          */
         public boolean hasSpecifiedSize() {
             return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
         }
+
+        /** @hide */
+        public void writeToParcel(Parcel dest) {
+            dest.writeInt(width);
+            dest.writeFloat(widthFraction);
+            dest.writeInt(height);
+            dest.writeFloat(heightFraction);
+            dest.writeInt(gravity);
+            dest.writeInt(minWidth);
+            dest.writeInt(minHeight);
+            dest.writeString(windowLayoutAffinity);
+        }
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a15afe0..c82fffa 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -25,6 +25,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ProcessInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -38,6 +39,8 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
 import com.android.server.SystemConfig;
 
 import java.lang.annotation.Retention;
@@ -56,7 +59,8 @@
  * &lt;application&gt; tag.
  */
 public class ApplicationInfo extends PackageItemInfo implements Parcelable {
-    
+    private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
+
     /**
      * Default task affinity of all activities in this application. See 
      * {@link ActivityInfo#taskAffinity} for more information.  This comes 
@@ -1273,6 +1277,14 @@
     public String zygotePreloadName;
 
     /**
+     * Indicates if the application has requested GWP-ASan to be enabled, disabled, or left
+     * unspecified. Processes can override this setting.
+     * @hide
+     */
+    @Nullable
+    public Boolean enableGwpAsan;
+
+    /**
      * Represents the default policy. The actual policy used will depend on other properties of
      * the application, e.g. the target SDK version.
      * @hide
@@ -1413,6 +1425,9 @@
             pw.println(prefix + "usesNonSdkApi=" + usesNonSdkApi());
             pw.println(prefix + "allowsPlaybackCapture="
                         + (isAudioPlaybackCaptureAllowed() ? "true" : "false"));
+            if (enableGwpAsan != null) {
+                pw.println(prefix + "enableGwpAsan=" + enableGwpAsan);
+            }
         }
         super.dumpBack(pw, prefix);
     }
@@ -1511,6 +1526,9 @@
             if (category != CATEGORY_UNDEFINED) {
                 proto.write(ApplicationInfoProto.Detail.CATEGORY, category);
             }
+            if (enableGwpAsan != null) {
+                proto.write(ApplicationInfoProto.Detail.ENABLE_GWP_ASAN, enableGwpAsan);
+            }
             proto.end(detailToken);
         }
         proto.end(token);
@@ -1620,6 +1638,7 @@
         mHiddenApiPolicy = orig.mHiddenApiPolicy;
         hiddenUntilInstalled = orig.hiddenUntilInstalled;
         zygotePreloadName = orig.zygotePreloadName;
+        enableGwpAsan = orig.enableGwpAsan;
     }
 
     public String toString() {
@@ -1703,6 +1722,7 @@
         dest.writeInt(mHiddenApiPolicy);
         dest.writeInt(hiddenUntilInstalled ? 1 : 0);
         dest.writeString(zygotePreloadName);
+        sForBoolean.parcel(enableGwpAsan, dest, parcelableFlags);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1783,6 +1803,7 @@
         mHiddenApiPolicy = source.readInt();
         hiddenUntilInstalled = source.readInt() != 0;
         zygotePreloadName = source.readString();
+        enableGwpAsan = sForBoolean.unparcel(source);
     }
 
     /**
@@ -2161,6 +2182,7 @@
     /** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; }
     /** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; }
     /** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; }
+    /** {@hide} */ public void setGwpAsanEnabled(@Nullable Boolean value) { enableGwpAsan = value; }
 
     /** {@hide} */
     @UnsupportedAppUsage
@@ -2172,4 +2194,6 @@
     @UnsupportedAppUsage
     public String getBaseResourcePath() { return publicSourceDir; }
     /** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; }
+    @Nullable
+    public Boolean isGwpAsanEnabled() { return enableGwpAsan; }
 }
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 5e7e0c8..dc3a0297 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -96,7 +96,7 @@
             mService.startActivityAsUser(
                     mContext.getIApplicationThread(),
                     mContext.getPackageName(),
-                    mContext.getFeatureId(),
+                    mContext.getAttributionTag(),
                     component,
                     targetUser.getIdentifier(),
                     true);
@@ -162,7 +162,7 @@
             mService.startActivityAsUserByIntent(
                     mContext.getIApplicationThread(),
                     mContext.getPackageName(),
-                    mContext.getFeatureId(),
+                    mContext.getAttributionTag(),
                     intent,
                     targetUser.getIdentifier(),
                     callingActivity != null ? callingActivity.getActivityToken() : null,
@@ -190,7 +190,7 @@
     public void startActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
         try {
             mService.startActivityAsUser(mContext.getIApplicationThread(),
-                    mContext.getPackageName(), mContext.getFeatureId(), component,
+                    mContext.getPackageName(), mContext.getAttributionTag(), component,
                     targetUser.getIdentifier(), false);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 8c3eef2..0311120 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -748,4 +748,6 @@
     void clearMimeGroup(String packageName, String group);
 
     List<String> getMimeGroup(String packageName, String group);
+
+    boolean isAutoRevokeWhitelisted(String packageName);
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 86242fd..4e4897f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -721,7 +721,7 @@
         }
         try {
             mService.startActivityAsUser(mContext.getIApplicationThread(),
-                    mContext.getPackageName(), mContext.getFeatureId(),
+                    mContext.getPackageName(), mContext.getAttributionTag(),
                     component, sourceBounds, opts, user);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
@@ -739,8 +739,8 @@
             @Nullable Rect sourceBounds, @Nullable Bundle opts) {
         try {
             mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
-                    mContext.getPackageName(), mContext.getFeatureId(), sessionInfo, sourceBounds,
-                    opts, sessionInfo.getUser());
+                    mContext.getPackageName(), mContext.getAttributionTag(), sessionInfo,
+                    sourceBounds, opts, sessionInfo.getUser());
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -760,7 +760,7 @@
         logErrorForInvalidProfileAccess(user);
         try {
             mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
-                    mContext.getPackageName(), mContext.getFeatureId(),
+                    mContext.getPackageName(), mContext.getAttributionTag(),
                     component, sourceBounds, opts, user);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index ec3590f..50bee85 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -16,6 +16,10 @@
 
 package android.content.pm;
 
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_IGNORED;
+
 import android.Manifest;
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.IntDef;
@@ -1456,6 +1460,8 @@
         /** {@hide} */
         public List<String> whitelistedRestrictedPermissions;
         /** {@hide} */
+        public int autoRevokePermissionsMode = MODE_DEFAULT;
+        /** {@hide} */
         public String installerPackageName;
         /** {@hide} */
         public boolean isMultiPackage;
@@ -1498,6 +1504,7 @@
             volumeUuid = source.readString();
             grantedRuntimePermissions = source.readStringArray();
             whitelistedRestrictedPermissions = source.createStringArrayList();
+            autoRevokePermissionsMode = source.readInt();
             installerPackageName = source.readString();
             isMultiPackage = source.readBoolean();
             isStaged = source.readBoolean();
@@ -1528,6 +1535,7 @@
             ret.volumeUuid = volumeUuid;
             ret.grantedRuntimePermissions = grantedRuntimePermissions;
             ret.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
+            ret.autoRevokePermissionsMode = autoRevokePermissionsMode;
             ret.installerPackageName = installerPackageName;
             ret.isMultiPackage = isMultiPackage;
             ret.isStaged = isStaged;
@@ -1691,6 +1699,22 @@
         }
 
         /**
+         * Sets whether permissions should be auto-revoked if this package is unused for an
+         * extended periodd of time.
+         *
+         * It's disabled by default but generally the installer should enable it for most packages,
+         * excluding only those where doing so might cause breakage that cannot be easily addressed
+         * by simply re-requesting the permission(s).
+         *
+         * If user explicitly enabled or disabled it via settings, this call is ignored.
+         *
+         * @param shouldAutoRevoke whether permissions should be auto-revoked.
+         */
+        public void setAutoRevokePermissionsMode(boolean shouldAutoRevoke) {
+            autoRevokePermissionsMode = shouldAutoRevoke ? MODE_ALLOWED : MODE_IGNORED;
+        }
+
+        /**
          * Request that rollbacks be enabled or disabled for the given upgrade with rollback data
          * policy set to RESTORE.
          *
@@ -1932,6 +1956,7 @@
             pw.printPair("volumeUuid", volumeUuid);
             pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
             pw.printPair("whitelistedRestrictedPermissions", whitelistedRestrictedPermissions);
+            pw.printPair("autoRevokePermissions", autoRevokePermissionsMode);
             pw.printPair("installerPackageName", installerPackageName);
             pw.printPair("isMultiPackage", isMultiPackage);
             pw.printPair("isStaged", isStaged);
@@ -1964,6 +1989,7 @@
             dest.writeString(volumeUuid);
             dest.writeStringArray(grantedRuntimePermissions);
             dest.writeStringList(whitelistedRestrictedPermissions);
+            dest.writeInt(autoRevokePermissionsMode);
             dest.writeString(installerPackageName);
             dest.writeBoolean(isMultiPackage);
             dest.writeBoolean(isStaged);
@@ -2085,6 +2111,8 @@
         public String[] grantedRuntimePermissions;
         /** {@hide}*/
         public List<String> whitelistedRestrictedPermissions;
+        /** {@hide}*/
+        public int autoRevokePermissionsMode = MODE_DEFAULT;
         /** {@hide} */
         public int installFlags;
         /** {@hide} */
@@ -2147,6 +2175,7 @@
             referrerUri = source.readParcelable(null);
             grantedRuntimePermissions = source.readStringArray();
             whitelistedRestrictedPermissions = source.createStringArrayList();
+            autoRevokePermissionsMode = source.readInt();
 
             installFlags = source.readInt();
             isMultiPackage = source.readBoolean();
@@ -2374,6 +2403,24 @@
         }
 
         /**
+         * Get the status of whether permission auto-revocation should be allowed, ignored, or
+         * deferred to manifest data.
+         *
+         * @see android.app.AppOpsManager#MODE_ALLOWED
+         * @see android.app.AppOpsManager#MODE_IGNORED
+         * @see android.app.AppOpsManager#MODE_DEFAULT
+         *
+         * @return the status of auto-revoke for this package
+         *
+         * @hide
+         */
+        @TestApi
+        @SystemApi
+        public int getAutoRevokePermissionsMode() {
+            return autoRevokePermissionsMode;
+        }
+
+        /**
          * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}.
          *
          * @deprecated use {@link #getRequestDowngrade()}.
@@ -2660,6 +2707,7 @@
             dest.writeParcelable(referrerUri, flags);
             dest.writeStringArray(grantedRuntimePermissions);
             dest.writeStringList(whitelistedRestrictedPermissions);
+            dest.writeInt(autoRevokePermissionsMode);
             dest.writeInt(installFlags);
             dest.writeBoolean(isMultiPackage);
             dest.writeBoolean(isStaged);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7600a08..05ff830 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -557,7 +557,6 @@
      * Internal {@link PackageInfo} flag used to indicate that a package is a hidden system app.
      * @hide
      */
-    @SystemApi
     public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS =  0x20000000;
 
     /**
@@ -1978,7 +1977,7 @@
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device's main front and back cameras can stream
      * concurrently as described in  {@link
-     * android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds()}
+     * android.hardware.camera2.CameraManager#getConcurrentCameraIds()}
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_CAMERA_CONCURRENT = "android.hardware.camera.concurrent";
@@ -3411,12 +3410,13 @@
     public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
 
     /**
-     * Permission flags: Reserved for use by the permission controller.
-     *
+     * Permission flags: Reserved for use by the permission controller. The platform and any
+     * packages besides the permission controller should not assume any definition about these
+     * flags.
      * @hide
      */
     @SystemApi
-    public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = 1 << 28 | 1 << 29
+    public static final int FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = 1 << 28 | 1 << 29
             | 1 << 30 | 1 << 31;
 
     /**
@@ -4575,6 +4575,53 @@
     }
 
     /**
+     * Marks an application exempt from having its permissions be automatically revoked when
+     * the app is unused for an extended period of time.
+     *
+     * Only the installer on record that installed the given package, or a holder of
+     * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this.
+     *
+     * Packages start in whitelisted state, and it is the installer's responsibility to
+     * un-whitelist the packages it installs, unless auto-revoking permissions from that package
+     * would cause breakages beyond having to re-request the permission(s).
+     *
+     * @param packageName The app for which to set exemption.
+     * @param whitelisted Whether the app should be whitelisted.
+     *
+     * @return whether any change took effect.
+     *
+     * @see #isAutoRevokeWhitelisted
+     *
+     * @throws SecurityException if you you have no access to modify this.
+     */
+    @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS,
+            conditional = true)
+    public boolean setAutoRevokeWhitelisted(@NonNull String packageName, boolean whitelisted) {
+        return false;
+    }
+
+    /**
+     * Checks whether an application is exempt from having its permissions be automatically revoked
+     * when the app is unused for an extended period of time.
+     *
+     * Only the installer on record that installed the given package, or a holder of
+     * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this.
+     * @param packageName The app for which to set exemption.
+     *
+     * @return Whether the app is whitelisted.
+     *
+     * @see #setAutoRevokeWhitelisted
+     *
+     * @throws SecurityException if you you have no access to this.
+     */
+    @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS,
+            conditional = true)
+    public boolean isAutoRevokeWhitelisted(@NonNull String packageName) {
+        return false;
+    }
+
+
+    /**
      * Gets whether you should show UI with rationale for requesting a permission.
      * You should do this only if you do not have the permission and the context in
      * which the permission is requested does not clearly communicate to the user
@@ -7834,6 +7881,15 @@
     }
 
     /**
+     * @return whether this package is whitelisted from having its runtime permission be
+     *         auto-revoked if unused for an extended period of time.
+     */
+    public boolean isAutoRevokeWhitelisted() {
+        throw new UnsupportedOperationException(
+                "isAutoRevokeWhitelisted not implemented in subclass");
+    }
+
+    /**
      * Returns if the provided drawable represents the default activity icon provided by the system.
      *
      * PackageManager silently returns a default application icon for any package/activity if the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c6875a4..18f1343 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -55,7 +55,6 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
@@ -190,7 +189,7 @@
     public static final String TAG_OVERLAY = "overlay";
     public static final String TAG_PACKAGE = "package";
     public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
-    public static final String TAG_FEATURE = "feature";
+    public static final String TAG_ATTRIBUTION = "attribution";
     public static final String TAG_PERMISSION = "permission";
     public static final String TAG_PERMISSION_GROUP = "permission-group";
     public static final String TAG_PERMISSION_TREE = "permission-tree";
@@ -209,6 +208,8 @@
     public static final String TAG_USES_SPLIT = "uses-split";
 
     public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+    public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
+            "android.activity_window_layout_affinity";
 
     /**
      * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
@@ -4560,6 +4561,8 @@
             }
         }
 
+        resolveWindowLayout(a);
+
         if (!setExported) {
             a.info.exported = a.intents.size() > 0;
         }
@@ -4726,6 +4729,35 @@
                 height, heightFraction, gravity, minWidth, minHeight);
     }
 
+    /**
+     * Resolves values in {@link ActivityInfo.WindowLayout}.
+     *
+     * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
+     * Android R and some variants of pre-R.
+     */
+    private void resolveWindowLayout(Activity activity) {
+        // There isn't a metadata for us to fall back. Whatever is in layout is correct.
+        if (activity.metaData == null
+                || !activity.metaData.containsKey(METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
+            return;
+        }
+
+        final ActivityInfo aInfo = activity.info;
+        // Layout already specifies a value. We should just use that one.
+        if (aInfo.windowLayout != null && aInfo.windowLayout.windowLayoutAffinity != null) {
+            return;
+        }
+
+        String windowLayoutAffinity = activity.metaData.getString(
+                METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
+        if (aInfo.windowLayout == null) {
+            aInfo.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
+                    -1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
+                    Gravity.NO_GRAVITY, -1 /* minWidth */, -1 /* minHeight */);
+        }
+        aInfo.windowLayout.windowLayoutAffinity = windowLayoutAffinity;
+    }
+
     private Activity parseActivityAlias(Package owner, Resources res,
             XmlResourceParser parser, int flags, String[] outError,
             CachedComponentArgs cachedArgs)
diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java
index c77a267..a373067 100644
--- a/core/java/android/content/pm/ProcessInfo.java
+++ b/core/java/android/content/pm/ProcessInfo.java
@@ -23,66 +23,157 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+
 /**
  * Information about a process an app may run.  This corresponds to information collected from the
  * AndroidManifest.xml's &lt;permission-group&gt; tags.
  * @hide
  */
+@DataClass(genGetters = true, genSetters = false, genParcelable = true, genAidl = false,
+        genBuilder = false)
 public class ProcessInfo implements Parcelable {
     /**
      * The name of the process, fully-qualified based on the app's package name.
      */
+    @NonNull
     public String name;
 
     /**
      * If non-null, these are permissions that are not allowed in this process.
      */
     @Nullable
+    @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArraySet.class)
     public ArraySet<String> deniedPermissions;
 
-    public ProcessInfo(String name, ArraySet<String> deniedPermissions) {
-        this.name = name;
-        this.deniedPermissions = deniedPermissions;
-    }
+    /**
+     * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified.
+     */
+    @Nullable
+    public Boolean enableGwpAsan;
 
     @Deprecated
     public ProcessInfo(@NonNull ProcessInfo orig) {
         this.name = orig.name;
         this.deniedPermissions = orig.deniedPermissions;
+        this.enableGwpAsan = orig.enableGwpAsan;
     }
 
-    public int describeContents() {
-        return 0;
+
+
+    // 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/content/pm/ProcessInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new ProcessInfo.
+     *
+     * @param name
+     *   The name of the process, fully-qualified based on the app's package name.
+     * @param deniedPermissions
+     *   If non-null, these are permissions that are not allowed in this process.
+     * @param enableGwpAsan
+     *   Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified.
+     */
+    @DataClass.Generated.Member
+    public ProcessInfo(
+            @NonNull String name,
+            @Nullable ArraySet<String> deniedPermissions,
+            @Nullable Boolean enableGwpAsan) {
+        this.name = name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, name);
+        this.deniedPermissions = deniedPermissions;
+        this.enableGwpAsan = enableGwpAsan;
+
+        // onConstructed(); // You can define this method to get a callback
     }
 
-    public void writeToParcel(Parcel dest, int parcelableFlags) {
-        dest.writeString(this.name);
-        final int numDenied = this.deniedPermissions != null
-                ? this.deniedPermissions.size() : 0;
-        dest.writeInt(numDenied);
-        for (int i = 0; i < numDenied; i++) {
-            dest.writeString(this.deniedPermissions.valueAt(i));
+    @DataClass.Generated.Member
+    static Parcelling<ArraySet<String>> sParcellingForDeniedPermissions =
+            Parcelling.Cache.get(
+                    Parcelling.BuiltIn.ForInternedStringArraySet.class);
+    static {
+        if (sParcellingForDeniedPermissions == null) {
+            sParcellingForDeniedPermissions = Parcelling.Cache.put(
+                    new Parcelling.BuiltIn.ForInternedStringArraySet());
         }
     }
 
-    public static final @NonNull Creator<ProcessInfo> CREATOR =
-            new Creator<ProcessInfo>() {
-                public ProcessInfo createFromParcel(Parcel source) {
-                    return new ProcessInfo(source);
-                }
-                public ProcessInfo[] newArray(int size) {
-                    return new ProcessInfo[size];
-                }
-            };
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
 
-    private ProcessInfo(Parcel source) {
-        this.name = source.readString();
-        final int numDenied = source.readInt();
-        if (numDenied > 0) {
-            this.deniedPermissions = new ArraySet<>(numDenied);
-            for (int i = numDenied - 1; i >= 0; i--) {
-                this.deniedPermissions.add(TextUtils.safeIntern(source.readString()));
-            }
-        }
+        byte flg = 0;
+        if (deniedPermissions != null) flg |= 0x2;
+        if (enableGwpAsan != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeString(name);
+        sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags);
+        if (enableGwpAsan != null) dest.writeBoolean(enableGwpAsan);
     }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected ProcessInfo(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        String _name = in.readString();
+        ArraySet<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in);
+        Boolean _enableGwpAsan = (flg & 0x4) == 0 ? null : (Boolean) in.readBoolean();
+
+        this.name = _name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, name);
+        this.deniedPermissions = _deniedPermissions;
+        this.enableGwpAsan = _enableGwpAsan;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ProcessInfo> CREATOR
+            = new Parcelable.Creator<ProcessInfo>() {
+        @Override
+        public ProcessInfo[] newArray(int size) {
+            return new ProcessInfo[size];
+        }
+
+        @Override
+        public ProcessInfo createFromParcel(@NonNull Parcel in) {
+            return new ProcessInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1582840056156L,
+            codegenVersion = "1.0.15",
+            sourceFile = "frameworks/base/core/java/android/content/pm/ProcessInfo.java",
+            inputSignatures = "public @android.annotation.NonNull java.lang.String name\npublic @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArraySet.class) android.util.ArraySet<java.lang.String> deniedPermissions\npublic @android.annotation.Nullable java.lang.Boolean enableGwpAsan\nclass ProcessInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index aa93d80..1304ba8 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -24,7 +24,7 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.content.pm.parsing.component.ParsedPermission;
@@ -77,7 +77,7 @@
 
     ParsingPackage addProvider(ParsedProvider parsedProvider);
 
-    ParsingPackage addFeature(ParsedFeature permission);
+    ParsingPackage addAttribution(ParsedAttribution attribution);
 
     ParsingPackage addReceiver(ParsedActivity parsedReceiver);
 
@@ -191,7 +191,11 @@
     ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage);
 
     ParsingPackage setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging);
-  
+
+    ParsingPackage setDontAutoRevokePermissions(boolean dontAutoRevokePermissions);
+
+    ParsingPackage setAllowDontAutoRevokePermissions(boolean allowDontAutoRevokePermissions);
+
     ParsingPackage setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage);
 
     ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion);
@@ -236,6 +240,8 @@
 
     ParsingPackage setEnabled(boolean enabled);
 
+    ParsingPackage setGwpAsanEnabled(Boolean enableGwpAsan);
+
     ParsingPackage setCrossProfile(boolean crossProfile);
 
     ParsingPackage setFullBackupContent(int fullBackupContent);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index a9b72d0..3390f16 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -30,9 +30,10 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageParser;
+import android.content.pm.ProcessInfo;
 import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedFeature;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.content.pm.parsing.component.ParsedMainComponent;
@@ -243,7 +244,7 @@
     protected List<ParsedProvider> providers = emptyList();
 
     @NonNull
-    private List<ParsedFeature> features = emptyList();
+    private List<ParsedAttribution> attributions = emptyList();
 
     @NonNull
     protected List<ParsedPermission> permissions = emptyList();
@@ -404,8 +405,14 @@
     private boolean hasFragileUserData;
     private boolean cantSaveState;
     private boolean allowNativeHeapPointerTagging;
+    private boolean dontAutoRevokePermissions;
+    private boolean allowDontAutoRevokePermissions;
     private boolean preserveLegacyExternalStorage;
 
+    @Nullable
+    @DataClass.ParcelWith(ForBoolean.class)
+    protected Boolean enableGwpAsan = null;
+
     // TODO(chiuwinson): Non-null
     @Nullable
     private ArraySet<String> mimeGroups;
@@ -620,8 +627,8 @@
     }
 
     @Override
-    public ParsingPackageImpl addFeature(ParsedFeature feature) {
-        this.features = CollectionUtils.add(this.features, feature);
+    public ParsingPackageImpl addAttribution(ParsedAttribution attribution) {
+        this.attributions = CollectionUtils.add(this.attributions, attribution);
         return this;
     }
 
@@ -904,7 +911,7 @@
         appInfo.volumeUuid = volumeUuid;
         appInfo.zygotePreloadName = zygotePreloadName;
         appInfo.crossProfile = isCrossProfile();
-
+        appInfo.setGwpAsanEnabled(enableGwpAsan);
         appInfo.setBaseCodePath(baseCodePath);
         appInfo.setBaseResourcePath(baseCodePath);
         appInfo.setCodePath(codePath);
@@ -990,7 +997,7 @@
         dest.writeTypedList(this.receivers);
         dest.writeTypedList(this.services);
         dest.writeTypedList(this.providers);
-        dest.writeTypedList(this.features);
+        dest.writeTypedList(this.attributions);
         dest.writeTypedList(this.permissions);
         dest.writeTypedList(this.permissionGroups);
         dest.writeTypedList(this.instrumentations);
@@ -1084,8 +1091,11 @@
         dest.writeBoolean(this.hasFragileUserData);
         dest.writeBoolean(this.cantSaveState);
         dest.writeBoolean(this.allowNativeHeapPointerTagging);
+        dest.writeBoolean(this.dontAutoRevokePermissions);
+        dest.writeBoolean(this.allowDontAutoRevokePermissions);
         dest.writeBoolean(this.preserveLegacyExternalStorage);
         dest.writeArraySet(this.mimeGroups);
+        sForBoolean.parcel(this.enableGwpAsan, dest, flags);
     }
 
     public ParsingPackageImpl(Parcel in) {
@@ -1149,7 +1159,7 @@
         this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
         this.services = in.createTypedArrayList(ParsedService.CREATOR);
         this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
-        this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
+        this.attributions = in.createTypedArrayList(ParsedAttribution.CREATOR);
         this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
         this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
         this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
@@ -1241,8 +1251,11 @@
         this.hasFragileUserData = in.readBoolean();
         this.cantSaveState = in.readBoolean();
         this.allowNativeHeapPointerTagging = in.readBoolean();
+        this.dontAutoRevokePermissions = in.readBoolean();
+        this.allowDontAutoRevokePermissions = in.readBoolean();
         this.preserveLegacyExternalStorage = in.readBoolean();
         this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
+        this.enableGwpAsan = sForBoolean.unparcel(in);
     }
 
     public static final Parcelable.Creator<ParsingPackageImpl> CREATOR =
@@ -1509,8 +1522,8 @@
 
     @NonNull
     @Override
-    public List<ParsedFeature> getFeatures() {
-        return features;
+    public List<ParsedAttribution> getAttributions() {
+        return attributions;
     }
 
     @NonNull
@@ -1965,6 +1978,12 @@
     }
 
     @Override
+    @Nullable
+    public Boolean isGwpAsanEnabled() {
+        return enableGwpAsan;
+    }
+
+    @Override
     public boolean isPartiallyDirectBootAware() {
         return partiallyDirectBootAware;
     }
@@ -2010,6 +2029,16 @@
     }
 
     @Override
+    public boolean isDontAutoRevokePermmissions() {
+        return dontAutoRevokePermissions;
+    }
+
+    @Override
+    public boolean isAllowDontAutoRevokePermmissions() {
+        return allowDontAutoRevokePermissions;
+    }
+
+    @Override
     public boolean hasPreserveLegacyExternalStorage() {
         return preserveLegacyExternalStorage;
     }
@@ -2420,6 +2449,12 @@
     }
 
     @Override
+    public ParsingPackageImpl setGwpAsanEnabled(@Nullable Boolean value) {
+        enableGwpAsan = value;
+        return this;
+    }
+
+    @Override
     public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) {
         partiallyDirectBootAware = value;
         return this;
@@ -2474,6 +2509,18 @@
     }
 
     @Override
+    public ParsingPackageImpl setDontAutoRevokePermissions(boolean value) {
+        dontAutoRevokePermissions = value;
+        return this;
+    }
+
+    @Override
+    public ParsingPackageImpl setAllowDontAutoRevokePermissions(boolean value) {
+        allowDontAutoRevokePermissions = value;
+        return this;
+    }
+
+    @Override
     public ParsingPackageImpl setPreserveLegacyExternalStorage(boolean value) {
         preserveLegacyExternalStorage = value;
         return this;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 048b924..9c13c85 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -28,7 +28,7 @@
 import android.content.pm.PackageParser;
 import android.content.pm.ServiceInfo;
 import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.content.pm.parsing.component.ParsedPermission;
@@ -80,7 +80,7 @@
     List<ConfigurationInfo> getConfigPreferences();
 
     @NonNull
-    List<ParsedFeature> getFeatures();
+    List<ParsedAttribution> getAttributions();
 
     /**
      * @see PackageInfo#featureGroups
@@ -771,6 +771,12 @@
     /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING */
     boolean isAllowNativeHeapPointerTagging();
 
+    /** @see ApplicationInfo#PRIVATE_FLAG2_DONT_AUTO_REVOKE_PERMISSIONS */
+    boolean isDontAutoRevokePermmissions();
+
+    /** @see ApplicationInfo#PRIVATE_FLAG2_ALLOW_DONT_AUTO_REVOKE_PERMISSIONS */
+    boolean isAllowDontAutoRevokePermmissions();
+
     boolean hasPreserveLegacyExternalStorage();
 
     /**
@@ -840,6 +846,13 @@
     @Nullable
     Set<String> getMimeGroups();
 
+    /**
+     * @see ApplicationInfo#enableGwpAsan
+     * @see R.styleable#AndroidManifest_enableGwpAsan
+     */
+    @Nullable
+    public Boolean isGwpAsanEnabled();
+
     // TODO(b/135203078): Hide and enforce going through PackageInfoUtils
     ApplicationInfo toAppInfoWithoutState();
 }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b4f2159..e41ed85 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -40,6 +40,7 @@
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
@@ -48,8 +49,8 @@
 import android.content.pm.parsing.component.ComponentParseUtils;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedActivityUtils;
-import android.content.pm.parsing.component.ParsedFeature;
-import android.content.pm.parsing.component.ParsedFeatureUtils;
+import android.content.pm.parsing.component.ParsedAttribution;
+import android.content.pm.parsing.component.ParsedAttributionUtils;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedInstrumentationUtils;
 import android.content.pm.parsing.component.ParsedIntentInfo;
@@ -672,7 +673,7 @@
             );
         }
 
-        if (!ParsedFeature.isCombinationValid(pkg.getFeatures())) {
+        if (!ParsedAttribution.isCombinationValid(pkg.getAttributions())) {
             return input.error(
                     INSTALL_PARSE_FAILED_BAD_MANIFEST,
                     "Combination <feature> tags are not valid"
@@ -707,8 +708,9 @@
                 return parseOverlay(input, pkg, res, parser);
             case PackageParser.TAG_KEY_SETS:
                 return parseKeySets(input, pkg, res, parser);
-            case PackageParser.TAG_FEATURE:
-                return parseFeature(input, pkg, res, parser);
+            case "feature": // TODO moltmann: Remove
+            case PackageParser.TAG_ATTRIBUTION:
+                return parseAttribution(input, pkg, res, parser);
             case PackageParser.TAG_PERMISSION_GROUP:
                 return parsePermissionGroup(input, pkg, res, parser);
             case PackageParser.TAG_PERMISSION:
@@ -917,13 +919,15 @@
         return input.success(pkg);
     }
 
-    private static ParseResult<ParsingPackage> parseFeature(ParseInput input, ParsingPackage pkg,
-            Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
-        ParseResult<ParsedFeature> result = ParsedFeatureUtils.parseFeature(res, parser, input);
+    private static ParseResult<ParsingPackage> parseAttribution(ParseInput input,
+            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            throws IOException, XmlPullParserException {
+        ParseResult<ParsedAttribution> result = ParsedAttributionUtils.parseAttribution(res,
+                parser, input);
         if (result.isError()) {
             return input.error(result);
         }
-        return input.success(pkg.addFeature(result.getResult()));
+        return input.success(pkg.addAttribution(result.getResult()));
     }
 
     private static ParseResult<ParsingPackage> parsePermissionGroup(ParseInput input,
@@ -1660,6 +1664,11 @@
                     && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
                 return input.error("Invalid class loader name: " + classLoaderName);
             }
+
+            if (sa.hasValue(R.styleable.AndroidManifestApplication_enableGwpAsan)) {
+                pkg.setGwpAsanEnabled(
+                        sa.getBoolean(R.styleable.AndroidManifestApplication_enableGwpAsan, false));
+            }
         } finally {
             sa.recycle();
         }
@@ -1811,6 +1820,8 @@
                 .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
                 .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
                 .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
+                .setDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_requestDontAutoRevokePermissions, sa))
+                .setAllowDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_allowDontAutoRevokePermissions, sa))
                 // targetSdkVersion gated
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index d32171d..4c93d09 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -285,14 +285,8 @@
         dest.writeBundle(this.metaData);
 
         if (windowLayout != null) {
-            dest.writeBoolean(true);
-            dest.writeInt(windowLayout.width);
-            dest.writeFloat(windowLayout.widthFraction);
-            dest.writeInt(windowLayout.height);
-            dest.writeFloat(windowLayout.heightFraction);
-            dest.writeInt(windowLayout.gravity);
-            dest.writeInt(windowLayout.minWidth);
-            dest.writeInt(windowLayout.minHeight);
+            dest.writeInt(1);
+            windowLayout.writeToParcel(dest);
         } else {
             dest.writeBoolean(false);
         }
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 1dcf262..6e5c51a 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -17,16 +17,17 @@
 package android.content.pm.parsing.component;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
 import static android.content.pm.parsing.component.ComponentParseUtils.flag;
 
 import android.annotation.NonNull;
 import android.app.ActivityTaskManager;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageParser;
-
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -42,9 +43,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -379,6 +377,12 @@
             }
         }
 
+        ParseResult<ActivityInfo.WindowLayout> layoutResult = resolveWindowLayout(activity, input);
+        if (layoutResult.isError()) {
+            return input.error(layoutResult);
+        }
+        activity.windowLayout = layoutResult.getResult();
+
         if (!setExported) {
             activity.exported = activity.getIntents().size() > 0;
         }
@@ -481,4 +485,35 @@
             sw.recycle();
         }
     }
+
+    /**
+     * Resolves values in {@link ActivityInfo.WindowLayout}.
+     *
+     * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
+     * Android R and some variants of pre-R.
+     */
+    private static ParseResult<ActivityInfo.WindowLayout> resolveWindowLayout(
+            ParsedActivity activity, ParseInput input) {
+        // There isn't a metadata for us to fall back. Whatever is in layout is correct.
+        if (activity.metaData == null || !activity.metaData.containsKey(
+                PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
+            return input.success(activity.windowLayout);
+        }
+
+        // Layout already specifies a value. We should just use that one.
+        if (activity.windowLayout != null && activity.windowLayout.windowLayoutAffinity != null) {
+            return input.success(activity.windowLayout);
+        }
+
+        String windowLayoutAffinity = activity.metaData.getString(
+                PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
+        ActivityInfo.WindowLayout layout = activity.windowLayout;
+        if (layout == null) {
+            layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */,
+                    -1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY,
+                    -1 /* minWidth */, -1 /* minHeight */);
+        }
+        layout.windowLayoutAffinity = windowLayoutAffinity;
+        return input.success(layout);
+    }
 }
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
new file mode 100644
index 0000000..02b3c7d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -0,0 +1,229 @@
+/*
+ * 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.content.pm.parsing.component;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link android.R.styleable#AndroidManifestAttribution &lt;attribution&gt;} tag parsed from the
+ * manifest.
+ *
+ * @hide
+ */
+@DataClass(genAidl = false)
+public class ParsedAttribution implements Parcelable {
+    /** Maximum length of attribution tag */
+    public static final int MAX_ATTRIBUTION_TAG_LEN = 50;
+
+    /** Maximum amount of attributions per package */
+    private static final int MAX_NUM_ATTRIBUTIONS = 1000;
+
+    /** Tag of the attribution */
+    public final @NonNull String tag;
+
+    /** User visible label fo the attribution */
+    public final @StringRes int label;
+
+    /** Ids of previously declared attributions this attribution inherits from */
+    public final @NonNull List<String> inheritFrom;
+
+    /**
+     * @return Is this set of attributions a valid combination for a single package?
+     */
+    public static boolean isCombinationValid(@Nullable List<ParsedAttribution> attributions) {
+        if (attributions == null) {
+            return true;
+        }
+
+        ArraySet<String> attributionTags = new ArraySet<>(attributions.size());
+        ArraySet<String> inheritFromAttributionTags = new ArraySet<>();
+
+        int numAttributions = attributions.size();
+        if (numAttributions > MAX_NUM_ATTRIBUTIONS) {
+            return false;
+        }
+
+        for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+            boolean wasAdded = attributionTags.add(attributions.get(attributionNum).tag);
+            if (!wasAdded) {
+                // feature id is not unique
+                return false;
+            }
+        }
+
+        for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+            ParsedAttribution feature = attributions.get(attributionNum);
+
+            int numInheritFrom = feature.inheritFrom.size();
+            for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
+                String inheritFrom = feature.inheritFrom.get(inheritFromNum);
+
+                if (attributionTags.contains(inheritFrom)) {
+                    // Cannot inherit from a attribution that is still defined
+                    return false;
+                }
+
+                boolean wasAdded = inheritFromAttributionTags.add(inheritFrom);
+                if (!wasAdded) {
+                    // inheritFrom is not unique
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+
+    // Code below generated by codegen v1.0.14.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @android.annotation.IntDef(prefix = "MAX_", value = {
+        MAX_ATTRIBUTION_TAG_LEN,
+        MAX_NUM_ATTRIBUTIONS
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Max {}
+
+    @DataClass.Generated.Member
+    public static String maxToString(@Max int value) {
+        switch (value) {
+            case MAX_ATTRIBUTION_TAG_LEN:
+                    return "MAX_ATTRIBUTION_TAG_LEN";
+            case MAX_NUM_ATTRIBUTIONS:
+                    return "MAX_NUM_ATTRIBUTIONS";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new ParsedAttribution.
+     *
+     * @param tag
+     *   Tag of the attribution
+     * @param label
+     *   User visible label fo the attribution
+     * @param inheritFrom
+     *   Ids of previously declared attributions this attribution inherits from
+     */
+    @DataClass.Generated.Member
+    public ParsedAttribution(
+            @NonNull String tag,
+            @StringRes int label,
+            @NonNull List<String> inheritFrom) {
+        this.tag = tag;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, tag);
+        this.label = label;
+        com.android.internal.util.AnnotationValidations.validate(
+                StringRes.class, null, label);
+        this.inheritFrom = inheritFrom;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, inheritFrom);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeString(tag);
+        dest.writeInt(label);
+        dest.writeStringList(inheritFrom);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected ParsedAttribution(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        String _tag = in.readString();
+        int _label = in.readInt();
+        List<String> _inheritFrom = new ArrayList<>();
+        in.readStringList(_inheritFrom);
+
+        this.tag = _tag;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, tag);
+        this.label = _label;
+        com.android.internal.util.AnnotationValidations.validate(
+                StringRes.class, null, label);
+        this.inheritFrom = _inheritFrom;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, inheritFrom);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ParsedAttribution> CREATOR
+            = new Parcelable.Creator<ParsedAttribution>() {
+        @Override
+        public ParsedAttribution[] newArray(int size) {
+            return new ParsedAttribution[size];
+        }
+
+        @Override
+        public ParsedAttribution createFromParcel(@NonNull Parcel in) {
+            return new ParsedAttribution(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1583436566499L,
+            codegenVersion = "1.0.14",
+            sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
+            inputSignatures = "public static final  int MAX_ATTRIBUTION_TAG_LEN\nprivate static final  int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static  boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java b/core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
similarity index 63%
rename from core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java
rename to core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
index fb52801..c4b1a0e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
@@ -34,34 +34,40 @@
 import java.util.List;
 
 /** @hide */
-public class ParsedFeatureUtils {
+public class ParsedAttributionUtils {
 
     @NonNull
-    public static ParseResult<ParsedFeature> parseFeature(Resources res, XmlResourceParser parser,
-            ParseInput input) throws IOException, XmlPullParserException {
-        String featureId;
+    public static ParseResult<ParsedAttribution> parseAttribution(Resources res,
+            XmlResourceParser parser, ParseInput input)
+            throws IOException, XmlPullParserException {
+        String attributionTag;
         int label;
         List<String> inheritFrom = null;
 
-        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAttribution);
         if (sa == null) {
-            return input.error("<feature> could not be parsed");
+            return input.error("<attribution> could not be parsed");
         }
 
         try {
-            featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
-                    0);
-            if (featureId == null) {
-                return input.error("<featureId> does not specify android:featureId");
+            attributionTag = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestAttribution_tag, 0);
+            if (attributionTag == null) {
+                // TODO moltmann: Remove handling of featureId
+                attributionTag = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestAttribution_featureId, 0);
+                if (attributionTag == null) {
+                    return input.error("<attribution> does not specify android:tag");
+                }
             }
-            if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
-                return input.error("<featureId> is too long. Max length is "
-                        + ParsedFeature.MAX_FEATURE_ID_LEN);
+            if (attributionTag.length() > ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN) {
+                return input.error("android:tag is too long. Max length is "
+                        + ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN);
             }
 
-            label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
+            label = sa.getResourceId(R.styleable.AndroidManifestAttribution_label, 0);
             if (label == Resources.ID_NULL) {
-                return input.error("<featureId> does not specify android:label");
+                return input.error("<attribution> does not specify android:label");
             }
         } finally {
             sa.recycle();
@@ -77,14 +83,15 @@
 
             String tagName = parser.getName();
             if (tagName.equals("inherit-from")) {
-                sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
+                sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestAttributionInheritFrom);
                 if (sa == null) {
                     return input.error("<inherit-from> could not be parsed");
                 }
 
                 try {
                     String inheritFromId = sa.getNonConfigurationString(
-                            R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
+                            R.styleable.AndroidManifestAttributionInheritFrom_tag, 0);
 
                     if (inheritFrom == null) {
                         inheritFrom = new ArrayList<>();
@@ -94,7 +101,7 @@
                     sa.recycle();
                 }
             } else {
-                return input.error("Bad element under <feature>: " + tagName);
+                return input.error("Bad element under <attribution>: " + tagName);
             }
         }
 
@@ -104,6 +111,6 @@
             ((ArrayList) inheritFrom).trimToSize();
         }
 
-        return input.success(new ParsedFeature(featureId, label, inheritFrom));
+        return input.success(new ParsedAttribution(attributionTag, label, inheritFrom));
     }
 }
diff --git a/core/java/android/content/pm/parsing/component/ParsedFeature.java b/core/java/android/content/pm/parsing/component/ParsedFeature.java
deleted file mode 100644
index b8a9098..0000000
--- a/core/java/android/content/pm/parsing/component/ParsedFeature.java
+++ /dev/null
@@ -1,229 +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 android.content.pm.parsing.component;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArraySet;
-
-import com.android.internal.util.DataClass;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A {@link android.R.styleable#AndroidManifestFeature &lt;feature&gt;} tag parsed from the
- * manifest.
- *
- * @hide
- */
-@DataClass(genAidl = false)
-public class ParsedFeature implements Parcelable {
-    /** Maximum length of featureId */
-    public static final int MAX_FEATURE_ID_LEN = 50;
-
-    /** Maximum amount of features per package */
-    private static final int MAX_NUM_FEATURES = 1000;
-
-    /** Id of the feature */
-    public final @NonNull String id;
-
-    /** User visible label fo the feature */
-    public final @StringRes int label;
-
-    /** Ids of previously declared features this feature inherits from */
-    public final @NonNull List<String> inheritFrom;
-
-    /**
-     * @return Is this set of features a valid combination for a single package?
-     */
-    public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
-        if (features == null) {
-            return true;
-        }
-
-        ArraySet<String> featureIds = new ArraySet<>(features.size());
-        ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
-
-        int numFeatures = features.size();
-        if (numFeatures > MAX_NUM_FEATURES) {
-            return false;
-        }
-
-        for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-            boolean wasAdded = featureIds.add(features.get(featureNum).id);
-            if (!wasAdded) {
-                // feature id is not unique
-                return false;
-            }
-        }
-
-        for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-            ParsedFeature feature = features.get(featureNum);
-
-            int numInheritFrom = feature.inheritFrom.size();
-            for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
-                String inheritFrom = feature.inheritFrom.get(inheritFromNum);
-
-                if (featureIds.contains(inheritFrom)) {
-                    // Cannot inherit from a feature that is still defined
-                    return false;
-                }
-
-                boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
-                if (!wasAdded) {
-                    // inheritFrom is not unique
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
-
-
-    // Code below generated by codegen v1.0.14.
-    //
-    // DO NOT MODIFY!
-    // CHECKSTYLE:OFF Generated code
-    //
-    // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java
-    //
-    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
-    //   Settings > Editor > Code Style > Formatter Control
-    //@formatter:off
-
-
-    @android.annotation.IntDef(prefix = "MAX_", value = {
-        MAX_FEATURE_ID_LEN,
-        MAX_NUM_FEATURES
-    })
-    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
-    @DataClass.Generated.Member
-    public @interface Max {}
-
-    @DataClass.Generated.Member
-    public static String maxToString(@Max int value) {
-        switch (value) {
-            case MAX_FEATURE_ID_LEN:
-                    return "MAX_FEATURE_ID_LEN";
-            case MAX_NUM_FEATURES:
-                    return "MAX_NUM_FEATURES";
-            default: return Integer.toHexString(value);
-        }
-    }
-
-    /**
-     * Creates a new ParsedFeature.
-     *
-     * @param id
-     *   Id of the feature
-     * @param label
-     *   User visible label fo the feature
-     * @param inheritFrom
-     *   Ids of previously declared features this feature inherits from
-     */
-    @DataClass.Generated.Member
-    public ParsedFeature(
-            @NonNull String id,
-            @StringRes int label,
-            @NonNull List<String> inheritFrom) {
-        this.id = id;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, id);
-        this.label = label;
-        com.android.internal.util.AnnotationValidations.validate(
-                StringRes.class, null, label);
-        this.inheritFrom = inheritFrom;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, inheritFrom);
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        // You can override field parcelling by defining methods like:
-        // void parcelFieldName(Parcel dest, int flags) { ... }
-
-        dest.writeString(id);
-        dest.writeInt(label);
-        dest.writeStringList(inheritFrom);
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public int describeContents() { return 0; }
-
-    /** @hide */
-    @SuppressWarnings({"unchecked", "RedundantCast"})
-    @DataClass.Generated.Member
-    protected ParsedFeature(@NonNull Parcel in) {
-        // You can override field unparcelling by defining methods like:
-        // static FieldType unparcelFieldName(Parcel in) { ... }
-
-        String _id = in.readString();
-        int _label = in.readInt();
-        List<String> _inheritFrom = new ArrayList<>();
-        in.readStringList(_inheritFrom);
-
-        this.id = _id;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, id);
-        this.label = _label;
-        com.android.internal.util.AnnotationValidations.validate(
-                StringRes.class, null, label);
-        this.inheritFrom = _inheritFrom;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, inheritFrom);
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    @DataClass.Generated.Member
-    public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
-            = new Parcelable.Creator<ParsedFeature>() {
-        @Override
-        public ParsedFeature[] newArray(int size) {
-            return new ParsedFeature[size];
-        }
-
-        @Override
-        public ParsedFeature createFromParcel(@NonNull Parcel in) {
-            return new ParsedFeature(in);
-        }
-    };
-
-    @DataClass.Generated(
-            time = 1581379861853L,
-            codegenVersion = "1.0.14",
-            sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java",
-            inputSignatures = "public static final  int MAX_FEATURE_ID_LEN\nprivate static final  int MAX_NUM_FEATURES\npublic final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static  boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
-    @Deprecated
-    private void __metadata() {}
-
-
-    //@formatter:on
-    // End of generated code
-
-}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java
index da7bf98..3b6020a 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcess.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java
@@ -41,6 +41,9 @@
     @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
     protected Set<String> deniedPermissions = emptySet();
 
+    @Nullable
+    protected Boolean enableGwpAsan = null;
+
     public ParsedProcess() {
     }
 
@@ -71,13 +74,15 @@
     @DataClass.Generated.Member
     public ParsedProcess(
             @NonNull String name,
-            @NonNull Set<String> deniedPermissions) {
+            @NonNull Set<String> deniedPermissions,
+            @Nullable Boolean enableGwpAsan) {
         this.name = name;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, name);
         this.deniedPermissions = deniedPermissions;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, deniedPermissions);
+        this.enableGwpAsan = enableGwpAsan;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -93,6 +98,11 @@
     }
 
     @DataClass.Generated.Member
+    public @Nullable Boolean getEnableGwpAsan() {
+        return enableGwpAsan;
+    }
+
+    @DataClass.Generated.Member
     static Parcelling<Set<String>> sParcellingForDeniedPermissions =
             Parcelling.Cache.get(
                     Parcelling.BuiltIn.ForInternedStringSet.class);
@@ -109,8 +119,12 @@
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
+        byte flg = 0;
+        if (enableGwpAsan != null) flg |= 0x4;
+        dest.writeByte(flg);
         dest.writeString(name);
         sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags);
+        if (enableGwpAsan != null) dest.writeBoolean(enableGwpAsan);
     }
 
     @Override
@@ -124,8 +138,10 @@
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
+        byte flg = in.readByte();
         String _name = in.readString();
         Set<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in);
+        Boolean _enableGwpAsan = (flg & 0x4) == 0 ? null : (Boolean) in.readBoolean();
 
         this.name = _name;
         com.android.internal.util.AnnotationValidations.validate(
@@ -133,6 +149,7 @@
         this.deniedPermissions = _deniedPermissions;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, deniedPermissions);
+        this.enableGwpAsan = _enableGwpAsan;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -152,10 +169,10 @@
     };
 
     @DataClass.Generated(
-            time = 1581452315946L,
+            time = 1582589960479L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java",
-            inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\npublic  void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
+            inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprotected @android.annotation.Nullable java.lang.Boolean enableGwpAsan\npublic  void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
index 4825066..3820790 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
@@ -103,6 +103,11 @@
             if (proc.name == null || proc.name.length() <= 0) {
                 return input.error("<process> does not specify android:process");
             }
+
+            if (sa.hasValue(R.styleable.AndroidManifestProcess_enableGwpAsan)) {
+                proc.enableGwpAsan =
+                        sa.getBoolean(R.styleable.AndroidManifestProcess_enableGwpAsan, false);
+            }
         } finally {
             sa.recycle();
         }
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 61310f3..8bcaf82 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -35,7 +35,7 @@
     // Notifies that a biometric has been acquired.
     void onAcquired(int acquiredInfo, String message);
     // Notifies that the SystemUI dialog has been dismissed.
-    void onDialogDismissed(int reason);
+    void onDialogDismissed(int reason, in byte[] credentialAttestation);
     // Notifies that the user has pressed the "try again" button on SystemUI
     void onTryAgainPressed();
     // Notifies that the user has pressed the "use password" button on SystemUI
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index b3a1ee2..7e72b73d 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2884,12 +2884,12 @@
      * generated according to the documented
      * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each device
      * which has its Id present in the set returned by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds}.
+     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds}.
      * Clients can use the array as a quick reference to find an appropriate camera stream
      * combination.
      * The mandatory stream combination array will be {@code null} in case the device is not a part
      * of at least one set of combinations returned by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds}.</p>
+     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds}.</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      */
     @PublicKey
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index cc0c1a30..30ee326 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -681,7 +681,7 @@
      * </p>
      *
      *<p>Devices capable of streaming concurrently with other devices as described by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds} have the
+     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
      * following guaranteed streams (when streaming concurrently with other devices)</p>
      *
      * <table>
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index a091f84..e81c649 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -160,8 +160,8 @@
      * @throws CameraAccessException if the camera device has been disconnected.
      */
     @NonNull
-    public Set<Set<String>> getConcurrentStreamingCameraIds() throws CameraAccessException {
-        return CameraManagerGlobal.get().getConcurrentStreamingCameraIds();
+    public Set<Set<String>> getConcurrentCameraIds() throws CameraAccessException {
+        return CameraManagerGlobal.get().getConcurrentCameraIds();
     }
 
     /**
@@ -189,11 +189,11 @@
      *
      * @return {@code true} if the given combination of session configurations and corresponding
      *                      camera ids are concurrently supported by the camera sub-system,
-     *         {@code false} otherwise.
+     *         {@code false} otherwise OR if the set of camera devices provided is not a subset of
+     *                       those returned by {@link #getConcurrentCameraIds}.
      *
-     * @throws IllegalArgumentException if the set of camera devices provided is not a subset of
-     *                                  those returned by getConcurrentStreamingCameraIds()
      * @throws CameraAccessException if one of the camera devices queried is no longer connected.
+     *
      */
     @RequiresPermission(android.Manifest.permission.CAMERA)
     public boolean isConcurrentSessionConfigurationSupported(
@@ -486,7 +486,7 @@
                             "Camera service is currently unavailable");
                     }
                     cameraUser = cameraService.connectDevice(callbacks, cameraId,
-                            mContext.getOpPackageName(), mContext.getFeatureId(), uid);
+                            mContext.getOpPackageName(), mContext.getAttributionTag(), uid);
                 } else {
                     // Use legacy camera implementation for HAL1 devices
                     int id;
@@ -1183,7 +1183,7 @@
 
             try {
                 ConcurrentCameraIdCombination[] cameraIdCombinations =
-                        cameraService.getConcurrentStreamingCameraIds();
+                        cameraService.getConcurrentCameraIds();
                 for (ConcurrentCameraIdCombination comb : cameraIdCombinations) {
                     mConcurrentCameraIdCombinations.add(comb.getConcurrentCameraIdCombination());
                 }
@@ -1372,7 +1372,7 @@
             return cameraIds;
         }
 
-        public @NonNull Set<Set<String>> getConcurrentStreamingCameraIds() {
+        public @NonNull Set<Set<String>> getConcurrentCameraIds() {
             Set<Set<String>> concurrentStreamingCameraIds = null;
             synchronized (mLock) {
                 // Try to make sure we have an up-to-date list of concurrent camera devices.
@@ -1398,7 +1398,7 @@
 
             synchronized (mLock) {
                 // Go through all the elements and check if the camera ids are valid at least /
-                // belong to one of the combinations returned by getConcurrentStreamingCameraIds()
+                // belong to one of the combinations returned by getConcurrentCameraIds()
                 boolean subsetFound = false;
                 for (Set<String> combination : mConcurrentCameraIdCombinations) {
                     if (combination.containsAll(cameraIdsAndSessionConfigurations.keySet())) {
@@ -1406,9 +1406,9 @@
                     }
                 }
                 if (!subsetFound) {
-                    throw new IllegalArgumentException(
-                            "The set of camera ids provided is not a subset of"
-                            + "getConcurrentStreamingCameraIds");
+                    Log.v(TAG, "isConcurrentSessionConfigurationSupported called with a subset of"
+                            + "camera ids not returned by getConcurrentCameraIds");
+                    return false;
                 }
                 CameraIdAndSessionConfiguration [] cameraIdsAndConfigs =
                         new CameraIdAndSessionConfiguration[size];
@@ -1436,10 +1436,10 @@
 
       /**
         * Helper function to find out if a camera id is in the set of combinations returned by
-        * getConcurrentStreamingCameraIds()
+        * getConcurrentCameraIds()
         * @param cameraId the unique identifier of the camera device to query
         * @return Whether the camera device was found in the set of combinations returned by
-        *         getConcurrentStreamingCameraIds
+        *         getConcurrentCameraIds
         */
         public boolean cameraIdHasConcurrentStreamsLocked(String cameraId) {
             if (!mDeviceStatus.containsKey(cameraId)) {
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index f0fab6a..20d9c30 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -721,7 +721,7 @@
         /**
           * Retrieve a list of all available mandatory concurrent stream combinations.
           * This method should only be called for devices which are listed in combinations returned
-          * by CameraManager.getConcurrentStreamingCameraIds.
+          * by CameraManager.getConcurrentCameraIds.
           *
           * @return a non-modifiable list of supported mandatory concurrent stream combinations.
           */
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index d0091440..1710ccb 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -368,7 +368,14 @@
 
     /** Class that includes information for a suspected data stall on a specific Network */
     public static final class DataStallReport implements Parcelable {
+        /**
+         * Indicates that the Data Stall was detected using DNS events.
+         */
         public static final int DETECTION_METHOD_DNS_EVENTS = 1;
+
+        /**
+         * Indicates that the Data Stall was detected using TCP metrics.
+         */
         public static final int DETECTION_METHOD_TCP_METRICS = 2;
 
         /** @hide */
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index fc6954f..81735ac 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3222,7 +3222,9 @@
 
     /** {@hide} - returns the factory serial number */
     @UnsupportedAppUsage
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public int registerNetworkFactory(Messenger messenger, String name) {
         try {
             return mService.registerNetworkFactory(messenger, name);
@@ -3233,7 +3235,9 @@
 
     /** {@hide} */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public void unregisterNetworkFactory(Messenger messenger) {
         try {
             mService.unregisterNetworkFactory(messenger);
@@ -3253,7 +3257,9 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public int registerNetworkProvider(@NonNull NetworkProvider provider) {
         if (provider.getProviderId() != NetworkProvider.ID_NONE) {
             throw new IllegalStateException("NetworkProviders can only be registered once");
@@ -3276,7 +3282,9 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public void unregisterNetworkProvider(@NonNull NetworkProvider provider) {
         try {
             mService.unregisterNetworkProvider(provider.getMessenger());
@@ -3288,7 +3296,9 @@
 
 
     /** @hide exposed via the NetworkProvider class. */
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
         try {
             mService.declareNetworkRequestUnfulfillable(request);
@@ -3306,7 +3316,9 @@
      * Register a NetworkAgent with ConnectivityService.
      * @return Network corresponding to NetworkAgent.
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkAgentConfig config) {
         return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
@@ -3317,7 +3329,9 @@
      * Register a NetworkAgent with ConnectivityService.
      * @return Network corresponding to NetworkAgent.
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_FACTORY})
     public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
         try {
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 2b8b7e6..6c0ba2f 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -22,7 +22,6 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.net.util.IpUtils;
-import android.os.Parcel;
 import android.util.Log;
 
 import java.net.InetAddress;
@@ -30,7 +29,6 @@
 /**
  * Represents the actual packets that are sent by the
  * {@link android.net.SocketKeepalive} API.
- *
  * @hide
  */
 @SystemApi
@@ -54,6 +52,9 @@
     /** Packet data. A raw byte string of packet data, not including the link-layer header. */
     private final byte[] mPacket;
 
+    // Note: If you add new fields, please modify the parcelling code in the child classes.
+
+
     // This should only be constructed via static factory methods, such as
     // nattKeepalivePacket.
     /**
@@ -87,21 +88,4 @@
         return mPacket.clone();
     }
 
-    /** @hide */
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(srcAddress.getHostAddress());
-        out.writeString(dstAddress.getHostAddress());
-        out.writeInt(srcPort);
-        out.writeInt(dstPort);
-        out.writeByteArray(mPacket);
-    }
-
-    /** @hide */
-    protected KeepalivePacketData(Parcel in) {
-        srcAddress = NetworkUtils.numericToInetAddress(in.readString());
-        dstAddress = NetworkUtils.numericToInetAddress(in.readString());
-        srcPort = in.readInt();
-        dstPort = in.readInt();
-        mPacket = in.createByteArray();
-    }
 }
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index c5681cb..6f5471b 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -61,6 +61,7 @@
 public class Network implements Parcelable {
 
     /**
+     * The unique id of the network.
      * @hide
      */
     @SystemApi
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index fef353f..5c754a1 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -78,6 +78,7 @@
     /**
      * The ID of the {@link NetworkProvider} that created this object, or
      * {@link NetworkProvider#ID_NONE} if unknown.
+     * @hide
      */
     public final int providerId;
 
@@ -584,6 +585,7 @@
      *
      * @deprecated this is for backward compatibility only.
      * @param legacySubtype the legacy subtype.
+     * @hide
      */
     @Deprecated
     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
@@ -608,6 +610,7 @@
      *
      * @deprecated this is for backward compatibility only.
      * @param extraInfo the ExtraInfo.
+     * @hide
      */
     @Deprecated
     public void setLegacyExtraInfo(@Nullable final String extraInfo) {
@@ -711,6 +714,7 @@
     /**
      * Called when ConnectivityService request a bandwidth update. The parent factory
      * shall try to overwrite this method and produce a bandwidth update if capable.
+     * @hide
      */
     public void onBandwidthUpdateRequested() {
         pollLceData();
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index 7e2db4a..ca9328a 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -108,6 +108,7 @@
     /**
      *
      * @return whether the sign in to network notification is enabled by this configuration.
+     * @hide
      */
     public boolean isProvisioningNotificationEnabled() {
         return !provisioningNotificationDisabled;
@@ -122,6 +123,7 @@
 
     /**
      * @return the subscriber ID, or null if none.
+     * @hide
      */
     @Nullable
     public String getSubscriberId() {
@@ -138,6 +140,7 @@
 
     /**
      * @return whether NAT64 prefix detection is enabled.
+     * @hide
      */
     public boolean isNat64DetectionEnabled() {
         return !skip464xlat;
@@ -247,6 +250,7 @@
          * Sets the subscriber ID for this network.
          *
          * @return this builder, to facilitate chaining.
+         * @hide
          */
         @NonNull
         public Builder setSubscriberId(@Nullable String subscriberId) {
@@ -259,6 +263,7 @@
          * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
          *
          * @return this builder, to facilitate chaining.
+         * @hide
          */
         @NonNull
         public Builder disableNat64Detection() {
@@ -271,6 +276,7 @@
          * perform its own carrier-specific provisioning procedure.
          *
          * @return this builder, to facilitate chaining.
+         * @hide
          */
         @NonNull
         public Builder disableProvisioningNotification() {
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 83f9980..116e343 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -613,7 +613,6 @@
      * @return {@code true} if the network should be restricted.
      * @hide
      */
-    @SystemApi
     public boolean deduceRestrictedCapability() {
         // Check if we have any capability that forces the network to be restricted.
         final boolean forceRestrictedCapability =
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 14442a2..1922b6d 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -21,7 +21,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.ActivityManager;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -56,7 +55,6 @@
  * @hide
  */
 @SystemService(Context.NETWORK_POLICY_SERVICE)
-@SystemApi
 public class NetworkPolicyManager {
 
     /* POLICY_* are masks and can be ORed, although currently they are not.*/
@@ -162,11 +160,13 @@
 
     /**
      * Mask used to check if an override value is marked as unmetered.
+     * @hide
      */
     public static final int SUBSCRIPTION_OVERRIDE_UNMETERED = 1 << 0;
 
     /**
      * Mask used to check if an override value is marked as congested.
+     * @hide
      */
     public static final int SUBSCRIPTION_OVERRIDE_CONGESTED = 1 << 1;
 
@@ -294,7 +294,6 @@
 
     /** @hide */
     @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
-    @SystemApi
     public void registerSubscriptionCallback(@NonNull SubscriptionCallback callback) {
         if (callback == null) {
             throw new NullPointerException("Callback cannot be null.");
@@ -309,7 +308,6 @@
 
     /** @hide */
     @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
-    @SystemApi
     public void unregisterSubscriptionCallback(@NonNull SubscriptionCallback callback) {
         if (callback == null) {
             throw new NullPointerException("Callback cannot be null.");
@@ -373,6 +371,7 @@
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first
      * @param callingPackage the name of the package making the call.
+     * @hide
      */
     public void setSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
             @SubscriptionOverrideMask int overrideValue, long timeoutMillis,
@@ -391,6 +390,7 @@
      * @param subId the subscriber this relationship applies to.
      * @param plans the list of plans.
      * @param callingPackage the name of the package making the call
+     * @hide
      */
     public void setSubscriptionPlans(int subId, @NonNull SubscriptionPlan[] plans,
             @NonNull String callingPackage) {
@@ -406,6 +406,7 @@
      *
      * @param subId the subscriber to get the subscription plans for.
      * @param callingPackage the name of the package making the call.
+     * @hide
      */
     @NonNull
     public SubscriptionPlan[] getSubscriptionPlans(int subId, @NonNull String callingPackage) {
@@ -549,7 +550,6 @@
     }
 
     /** @hide */
-    @SystemApi
     public static class SubscriptionCallback {
         /**
          * Notify clients of a new override about a given subscription.
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index 2c0e4aa..418d691 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -106,10 +106,12 @@
     }
 
     // TODO: consider adding a register() method so ConnectivityManager does not need to call this.
+    /** @hide */
     public @Nullable Messenger getMessenger() {
         return mMessenger;
     }
 
+    /** @hide */
     public @NonNull String getName() {
         return mName;
     }
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 9ca1c33..fab906b 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -157,20 +157,20 @@
             Preconditions.checkNotNull(executor);
             Preconditions.checkNotNull(callback);
 
-            boolean validScreenshotFd = screenshotFd != null;
+            boolean isScreenshotRequested = screenshotFd != null;
             if (screenshotFd == null) {
                 // Binder needs a valid File Descriptor to be passed
                 screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"),
                         ParcelFileDescriptor.MODE_READ_ONLY);
             }
             DumpstateListener dsListener = new DumpstateListener(executor, callback,
-                    validScreenshotFd);
+                    isScreenshotRequested);
             // Note: mBinder can get callingUid from the binder transaction.
             mBinder.startBugreport(-1 /* callingUid */,
                     mContext.getOpPackageName(),
                     bugreportFd.getFileDescriptor(),
                     screenshotFd.getFileDescriptor(),
-                    params.getMode(), dsListener);
+                    params.getMode(), dsListener, isScreenshotRequested);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (FileNotFoundException e) {
@@ -225,13 +225,13 @@
     private final class DumpstateListener extends IDumpstateListener.Stub {
         private final Executor mExecutor;
         private final BugreportCallback mCallback;
-        private final boolean mValidScreenshotFd;
+        private final boolean mIsScreenshotRequested;
 
         DumpstateListener(Executor executor, BugreportCallback callback,
-                boolean validScreenshotFd) {
+                boolean isScreenshotRequested) {
             mExecutor = executor;
             mCallback = callback;
-            mValidScreenshotFd = validScreenshotFd;
+            mIsScreenshotRequested = isScreenshotRequested;
         }
 
         @Override
@@ -272,7 +272,7 @@
 
         @Override
         public void onScreenshotTaken(boolean success) throws RemoteException {
-            if (!mValidScreenshotFd) {
+            if (!mIsScreenshotRequested) {
                 return;
             }
 
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 9c999b2..590fbb3 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 
 /**
@@ -114,20 +115,36 @@
             = "android.os.action.UPDATE_CARRIER_ID_DB";
 
     /**
-    * Broadcast intent action indicating that the updated emergency number database is available.
-    * <p>Extra: "VERSION" the numeric version of the new data. Devices should only install if the
-    * update version is newer than the current one.
-    * <p>Extra: "REQUIRED_HASH" the hash of the current update data.
-    * <p>Input: {@link android.content.Intent#getData} is URI of downloaded emergency number file.
-    * Devices should pick up the downloaded file and persist to the database
-    * {@code com.android.internal.telephony.emergency.EmergencyNumberTracker}.
+    * Update the emergency number database into the devices.
+    * <p>Extra: {@link #EXTRA_VERSION} the numeric version of the database.
+    * <p>Extra: {@link #EXTRA_REQUIRED_HASH} the hash of the database.
+    * <p>Input: {@link android.content.Intent#getData} the URI to download emergency number
+    * database.
     *
     * @hide
     */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.UPDATE_CONFIG)
     public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB =
             "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
 
+    /**
+     * An integer to indicate the numeric version of the new data. Devices should only install
+     * if the update version is newer than the current one.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_VERSION = "android.os.extra.VERSION";
+
+    /**
+     * A string to indicate the hash of the data.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_REQUIRED_HASH = "android.os.extra.REQUIRED_HASH";
+
     private ConfigUpdate() {
     }
 }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f2fb5b2..09ccb72 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -23,6 +23,7 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
+import android.compat.Compatibility;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
@@ -88,6 +89,16 @@
     private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT,
             "/apex");
 
+    /**
+     * See definition in com.android.providers.media.LocalCallingIdentity
+     */
+    private static final long DEFAULT_SCOPED_STORAGE = 149924527L;
+
+    /**
+     * See definition in com.android.providers.media.LocalCallingIdentity
+     */
+    private static final long FORCE_ENABLE_SCOPED_STORAGE = 132649864L;
+
     @UnsupportedAppUsage
     private static UserEnvironment sCurrentUser;
     private static boolean sUserRequired;
@@ -1191,12 +1202,13 @@
     }
 
     /**
-     * Returns whether the primary shared/external storage media is a legacy
-     * view that includes files not owned by the app.
+     * Returns whether the shared/external storage media is a
+     * legacy view that includes files not owned by the app.
      * <p>
      * This value may be different from the value requested by
      * {@code requestLegacyExternalStorage} in the app's manifest, since an app
-     * may inherit its legacy state based on when it was first installed.
+     * may inherit its legacy state based on when it was first installed, target sdk and other
+     * factors.
      * <p>
      * Non-legacy apps can continue to discover and read media belonging to
      * other apps via {@link android.provider.MediaStore}.
@@ -1207,18 +1219,19 @@
     }
 
     /**
-     * Returns whether the shared/external storage media at the given path is a
+     * Returns whether the shared/external storage media is a
      * legacy view that includes files not owned by the app.
      * <p>
      * This value may be different from the value requested by
      * {@code requestLegacyExternalStorage} in the app's manifest, since an app
-     * may inherit its legacy state based on when it was first installed.
+     * may inherit its legacy state based on when it was first installed, target sdk and other
+     * factors.
      * <p>
      * Non-legacy apps can continue to discover and read media belonging to
      * other apps via {@link android.provider.MediaStore}.
      *
      * @throws IllegalArgumentException if the path is not a valid storage
-     *             device.
+     * device.
      */
     public static boolean isExternalStorageLegacy(@NonNull File path) {
         final Context context = AppGlobals.getInitialApplication();
@@ -1232,24 +1245,23 @@
             return false;
         }
 
-        if (packageManager.checkPermission(Manifest.permission.WRITE_MEDIA_STORAGE,
-                context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+        // TODO(b/150672994): Compat flags do not override instant app and isolated process's
+        //  behavior.
+        boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE);
+        boolean forceEnableScopedStorage = Compatibility.isChangeEnabled(
+                FORCE_ENABLE_SCOPED_STORAGE);
+        // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access
+        // Note: does not require packagename/uid as this is directly called from an app process
+        if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) {
+            return false;
+        }
+        // if Scoped Storage is strictly disabled, the app has legacy storage access
+        // Note: does not require packagename/uid as this is directly called from an app process
+        if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) {
             return true;
         }
 
-        if (packageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES,
-                context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
-        final String[] packagesForUid = packageManager.getPackagesForUid(uid);
-        for (String packageName : packagesForUid) {
-            if (appOps.checkOpNoThrow(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
-                    uid, packageName) == AppOpsManager.MODE_ALLOWED) {
-                return true;
-            }
-        }
-
         return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
                 uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
     }
@@ -1298,6 +1310,16 @@
         }
     }
 
+    private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
+            boolean forceEnableScopedStorage) {
+        return defaultScopedStorage && forceEnableScopedStorage;
+    }
+
+    private static boolean isScopedStorageDisabled(boolean defaultScopedStorage,
+            boolean forceEnableScopedStorage) {
+        return !defaultScopedStorage && !forceEnableScopedStorage;
+    }
+
     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/os/Looper.java b/core/java/android/os/Looper.java
index b478dbe..a7e3263 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -77,6 +77,7 @@
     @UnsupportedAppUsage
     final MessageQueue mQueue;
     final Thread mThread;
+    private boolean mInLoop;
 
     @UnsupportedAppUsage
     private Printer mLogging;
@@ -155,6 +156,12 @@
         if (me == null) {
             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
         }
+        if (me.mInLoop) {
+            Slog.w(TAG, "Loop again would have the queued messages be executed"
+                    + " before this one completed.");
+        }
+
+        me.mInLoop = true;
         final MessageQueue queue = me.mQueue;
 
         // Make sure the identity of this thread is that of the local process,
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d7af1b9..a557bd9 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -607,6 +607,7 @@
      *                             started.
      * @param pkgDataInfoMap Map from related package names to private data directory
      *                       volume UUID and inode number.
+     * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * @return An object that describes the result of the attempt to start the process.
      * @throws RuntimeException on fatal start failure
@@ -630,12 +631,13 @@
                                            @Nullable long[] disabledCompatChanges,
                                            @Nullable Map<String, Pair<String, Long>>
                                                    pkgDataInfoMap,
+                                           boolean bindMountAppStorageDirs,
                                            @Nullable String[] zygoteArgs) {
         return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
                     zygotePolicyFlags, isTopApp, disabledCompatChanges,
-                    pkgDataInfoMap, zygoteArgs);
+                    pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
     }
 
     /** @hide */
@@ -659,7 +661,7 @@
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
                     /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false,
-                disabledCompatChanges, /* pkgDataInfoMap */ null, zygoteArgs);
+                disabledCompatChanges, /* pkgDataInfoMap */ null, false, zygoteArgs);
     }
 
     /**
diff --git a/core/java/android/os/Users.md b/core/java/android/os/Users.md
new file mode 100644
index 0000000..3bbbe54
--- /dev/null
+++ b/core/java/android/os/Users.md
@@ -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
+  -->
+
+# Users for system developers
+
+## Concepts
+
+### User
+
+A user of a device e.g. usually a human being. Each user has its own home screen.
+
+#### User Profile
+
+A user can have multiple profiles. E.g. one for the private life and one for work. Each profile
+has a different set of apps and accounts but they share one home screen. All profiles of a
+profile group can be active at the same time.
+
+Each profile has a separate [`userId`](#int-userid). Unless needed user profiles are treated as
+completely separate users.
+
+#### Profile Group
+
+All user profiles that share a home screen. You can list the profiles of a user via
+`UserManager#getEnabledProfiles` (you usually don't deal with disabled profiles)
+
+#### Foreground user vs background user
+
+Only a single user profile group can be in the foreground. This is the user profile the user
+currently interacts with.
+
+#### Parent user (profile)
+
+The main profile of a profile group, usually the personal (as opposed to work) profile. Get this via
+`UserManager#getProfileParent` (returns `null` if the user does not have profiles)
+
+#### Managed user (profile)
+
+The other profiles of a profile group. The name comes from the fact that these profiles are usually
+managed by a device policy controller app. You can create a managed profile from within the device
+policy controller app on your phone.
+
+#### Account
+
+An account of a user profile with a (usually internet based) service. E.g. aname@gmail.com or
+aname@yahoo.com. Each profile can have multiple accounts. A profile does not have to have a
+account.
+
+## Data types
+
+### int userId
+
+... usually marked as `@UserIdInt`
+
+The id of a user profile. List all users via `adb shell dumpsys user`. There is no data type for a
+user, all you can do is using the user id of the parent profile as a proxy for the user.
+
+### int uid
+
+Identity of an app. This is the same as a Linux uid, but in Android there is one uid per package,
+per user.
+
+It is highly discouraged, but uids can be shared between multiple packages using the
+`android:sharedUserId` manifest attribute.
+
+### class UserHandle
+
+A wrapper for userId. Used esp. in public APIs instead of `int userId` as it clearly distinguishes
+from uid.
+
+## Security model
+
+Multiple packages can share an uid by using `android:sharedUserId` manifest attribute. If packages
+share a uid they can run in the same process via `android:process` manifest attribute. Further file
+level access is also tracked by uid. Hence any security or privacy mechanism needs to be built on
+a uid granularity.
+
+On the other hand apps belonging to the same user cannot see each others files. They can only
+interact via activity launches, broadcasts, providers, and service bindings. All of them can be be
+protected by [permissions](../permission/Permissions.md). Hence any new general communication
+mechanism should be access controlled by permissions.
+
+## Lifecycle
+
+A system service should deal with users being started and stopped by overriding
+`SystemService.onSwitchUser` and `SystemService.onStopUser`.
+
+If users profiles become inactive the system should stop all apps of this profile from interacting
+with other apps or the system.
+
+Another important lifecycle event is `onUnlockUser`. Only for unlocked user profiles you can access
+all data, e.g. which packages are installed.
+
+You only want to deal with user profiles that
+
+- are in the profile group of the foreground user
+- the user profile is unlocked and not yet stopped
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 2d218f4..1992f1d 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -963,7 +963,7 @@
                 PRIMITIVE_QUICK_RISE,
                 PRIMITIVE_SLOW_RISE,
                 PRIMITIVE_QUICK_FALL,
-                PRIMITIVE_LIGHT_TICK,
+                PRIMITIVE_TICK,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface Primitive {}
@@ -981,10 +981,14 @@
          * A haptic effect that simulates downwards movement with gravity. Often
          * followed by extra energy of hitting and reverberation to augment
          * physicality.
+         *
+         * @hide Not confident enough to expose publicly yet
          */
         public static final int PRIMITIVE_THUD = 2;
         /**
          * A haptic effect that simulates spinning momentum.
+         *
+         * @hide Not confident enough to expose publicly yet
          */
         public static final int PRIMITIVE_SPIN = 3;
         /**
@@ -1003,7 +1007,8 @@
          * This very short effect should produce a light crisp sensation intended
          * to be used repetitively for dynamic feedback.
          */
-        public static final int PRIMITIVE_LIGHT_TICK = 7;
+        // Internally this maps to the HAL constant CompositePrimitive::LIGHT_TICK
+        public static final int PRIMITIVE_TICK = 7;
 
 
         private ArrayList<PrimitiveEffect> mEffects = new ArrayList<>();
@@ -1081,7 +1086,7 @@
          *
          */
         static int checkPrimitive(int primitiveId) {
-            Preconditions.checkArgumentInRange(primitiveId, PRIMITIVE_NOOP, PRIMITIVE_LIGHT_TICK,
+            Preconditions.checkArgumentInRange(primitiveId, PRIMITIVE_NOOP, PRIMITIVE_TICK,
                     "primitiveId");
             return primitiveId;
         }
@@ -1108,8 +1113,8 @@
                     return "PRIMITIVE_SLOW_RISE";
                 case PRIMITIVE_QUICK_FALL:
                     return "PRIMITIVE_QUICK_FALL";
-                case PRIMITIVE_LIGHT_TICK:
-                    return "PRIMITIVE_LIGHT_TICK";
+                case PRIMITIVE_TICK:
+                    return "PRIMITIVE_TICK";
 
                 default:
                     return Integer.toString(id);
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 34cec06..5f3f14f 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -333,6 +333,7 @@
      *                             started.
      * @param pkgDataInfoMap Map from related package names to private data directory
      *                       volume UUID and inode number.
+     * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
      *
      * @param zygoteArgs Additional arguments to supply to the Zygote process.
      * @return An object that describes the result of the attempt to start the process.
@@ -354,6 +355,7 @@
                                                   @Nullable long[] disabledCompatChanges,
                                                   @Nullable Map<String, Pair<String, Long>>
                                                           pkgDataInfoMap,
+                                                  boolean bindMountAppStorageDirs,
                                                   @Nullable String[] zygoteArgs) {
         // TODO (chriswailes): Is there a better place to check this value?
         if (fetchUsapPoolEnabledPropWithMinInterval()) {
@@ -365,7 +367,7 @@
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                     packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
-                    pkgDataInfoMap, zygoteArgs);
+                    pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -606,6 +608,7 @@
      * @param disabledCompatChanges a list of disabled compat changes for the process being started.
      * @param pkgDataInfoMap Map from related package names to private data directory volume UUID
      *                       and inode number.
+     * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
      * @param extraArgs Additional arguments to supply to the zygote process.
      * @return An object that describes the result of the attempt to start the process.
      * @throws ZygoteStartFailedEx if process start failed for any reason
@@ -628,6 +631,7 @@
                                                       @Nullable long[] disabledCompatChanges,
                                                       @Nullable Map<String, Pair<String, Long>>
                                                               pkgDataInfoMap,
+                                                      boolean bindMountAppStorageDirs,
                                                       @Nullable String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
         ArrayList<String> argsForZygote = new ArrayList<>();
@@ -725,6 +729,10 @@
             argsForZygote.add(sb.toString());
         }
 
+        if (bindMountAppStorageDirs) {
+            argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
+        }
+
         if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
             StringBuilder sb = new StringBuilder();
             sb.append("--disabled-compat-changes=");
@@ -1282,7 +1290,9 @@
                     abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
                     true /* startChildZygote */, null /* packageName */,
                     ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
-                    null /* disabledCompatChanges */, null /* pkgDataInfoMap */, extraArgs);
+                    null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
+                    /* bindMountAppStorageDirs */ false, extraArgs);
+
         } catch (ZygoteStartFailedEx ex) {
             throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
         }
diff --git a/core/java/android/os/incremental/IncrementalNewFileParams.aidl b/core/java/android/os/incremental/IncrementalNewFileParams.aidl
index 182732c..8faf158 100644
--- a/core/java/android/os/incremental/IncrementalNewFileParams.aidl
+++ b/core/java/android/os/incremental/IncrementalNewFileParams.aidl
@@ -16,8 +16,6 @@
 
 package android.os.incremental;
 
-import android.os.incremental.IncrementalSignature;
-
 /**
  * All the parameters to create a new file on IncFS
  * FileId is a 16 byte-long identifier.
@@ -27,5 +25,5 @@
     long size;
     byte[] fileId;
     byte[] metadata;
-    @nullable IncrementalSignature signature;
+    @nullable byte[] signature;
 }
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index bf31bc2..7092751 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -20,8 +20,6 @@
 import android.annotation.Nullable;
 import android.os.RemoteException;
 
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -180,11 +178,12 @@
             if (id == null && metadata == null) {
                 throw new IOException("File ID and metadata cannot both be null");
             }
+            validateV4Signature(v4signatureBytes);
             final IncrementalNewFileParams params = new IncrementalNewFileParams();
             params.size = size;
             params.metadata = (metadata == null ? new byte[0] : metadata);
             params.fileId = idToBytes(id);
-            params.signature = parseV4Signature(v4signatureBytes);
+            params.signature = v4signatureBytes;
             int res = mService.makeFile(mId, path, params);
             if (res != 0) {
                 throw new IOException("makeFile() failed with errno " + -res);
@@ -415,27 +414,23 @@
         return new UUID(msb, lsb);
     }
 
-    private static final int INCFS_HASH_SHA256 = 1;
     private static final int INCFS_MAX_HASH_SIZE = 32; // SHA256
     private static final int INCFS_MAX_ADD_DATA_SIZE = 128;
 
     /**
      * Deserialize and validate v4 signature bytes.
      */
-    private static IncrementalSignature parseV4Signature(@Nullable byte[] v4signatureBytes)
+    private static void validateV4Signature(@Nullable byte[] v4signatureBytes)
             throws IOException {
         if (v4signatureBytes == null || v4signatureBytes.length == 0) {
-            return null;
+            return;
         }
 
         final V4Signature signature;
-        try (DataInputStream input = new DataInputStream(
-                new ByteArrayInputStream(v4signatureBytes))) {
-            try {
-                signature = V4Signature.readFrom(input);
-            } catch (IOException e) {
-                throw new IOException("Failed to read v4 signature:", e);
-            }
+        try {
+            signature = V4Signature.readFrom(v4signatureBytes);
+        } catch (IOException e) {
+            throw new IOException("Failed to read v4 signature:", e);
         }
 
         if (!signature.isVersionSupported()) {
@@ -443,25 +438,27 @@
                     + " is not supported");
         }
 
-        final byte[] rootHash = signature.verityRootHash;
-        final byte[] additionalData = signature.v3Digest;
-        final byte[] pkcs7Signature = signature.pkcs7SignatureBlock;
+        final V4Signature.HashingInfo hashingInfo = V4Signature.HashingInfo.fromByteArray(
+                signature.hashingInfo);
+        final V4Signature.SigningInfo signingInfo = V4Signature.SigningInfo.fromByteArray(
+                signature.signingInfo);
 
-        if (rootHash.length != INCFS_MAX_HASH_SIZE) {
-            throw new IOException("rootHash has to be " + INCFS_MAX_HASH_SIZE + " bytes");
+        if (hashingInfo.hashAlgorithm != V4Signature.HASHING_ALGORITHM_SHA256) {
+            throw new IOException("Unsupported hashAlgorithm: " + hashingInfo.hashAlgorithm);
         }
-        if (additionalData.length > INCFS_MAX_ADD_DATA_SIZE) {
+        if (hashingInfo.log2BlockSize != V4Signature.LOG2_BLOCK_SIZE_4096_BYTES) {
+            throw new IOException("Unsupported log2BlockSize: " + hashingInfo.log2BlockSize);
+        }
+        if (hashingInfo.salt != null && hashingInfo.salt.length > 0) {
+            throw new IOException("Unsupported salt: " + hashingInfo.salt);
+        }
+        if (hashingInfo.rawRootHash.length != INCFS_MAX_HASH_SIZE) {
+            throw new IOException("rawRootHash has to be " + INCFS_MAX_HASH_SIZE + " bytes");
+        }
+        if (signingInfo.additionalData.length > INCFS_MAX_ADD_DATA_SIZE) {
             throw new IOException(
                     "additionalData has to be at most " + INCFS_MAX_ADD_DATA_SIZE + " bytes");
         }
-
-        IncrementalSignature result = new IncrementalSignature();
-        result.hashAlgorithm = INCFS_HASH_SHA256;
-        result.rootHash = rootHash;
-        result.additionalData = additionalData;
-        result.signature = pkcs7Signature;
-
-        return result;
     }
 
     /**
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index 6d334f5..71f931d 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -20,9 +20,12 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.EOFException;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 /**
  * V4 signature fields.
@@ -31,30 +34,95 @@
  */
 public class V4Signature {
     public static final String EXT = ".idsig";
-    public static final int SUPPORTED_VERSION = 1;
+    public static final int SUPPORTED_VERSION = 2;
 
-    public final int version;
-    public final byte[] verityRootHash;
-    public final byte[] v3Digest;
-    public final byte[] pkcs7SignatureBlock;
+    public static final int HASHING_ALGORITHM_SHA256 = 1;
+    public static final byte LOG2_BLOCK_SIZE_4096_BYTES = 12;
+
+    /**
+     * IncFS hashing data.
+     */
+    public static class HashingInfo {
+        public final int hashAlgorithm; // only 1 == SHA256 supported
+        public final byte log2BlockSize; // only 12 (block size 4096) supported now
+        public final byte[] salt; // used exactly as in fs-verity, 32 bytes max
+        public final byte[] rawRootHash; // salted digest of the first Merkle tree page
+
+        HashingInfo(int hashAlgorithm, byte log2BlockSize, byte[] salt, byte[] rawRootHash) {
+            this.hashAlgorithm = hashAlgorithm;
+            this.log2BlockSize = log2BlockSize;
+            this.salt = salt;
+            this.rawRootHash = rawRootHash;
+        }
+
+        /**
+         * Constructs HashingInfo from byte array.
+         */
+        public static HashingInfo fromByteArray(byte[] bytes) throws IOException {
+            ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+            final int hashAlgorithm = buffer.getInt();
+            final byte log2BlockSize = buffer.get();
+            byte[] salt = readBytes(buffer);
+            byte[] rawRootHash = readBytes(buffer);
+            return new HashingInfo(hashAlgorithm, log2BlockSize, salt, rawRootHash);
+        }
+    }
+
+    /**
+     * V4 signature data.
+     */
+    public static class SigningInfo {
+        public final byte[] v3Digest;  // used to match with the corresponding APK
+        public final byte[] certificate; // ASN.1 DER form
+        public final byte[] additionalData; // a free-form binary data blob
+        public final byte[] publicKey; // ASN.1 DER, must match the certificate
+        public final int signatureAlgorithmId; // see the APK v2 doc for the list
+        public final byte[] signature;
+
+        SigningInfo(byte[] v3Digest, byte[] certificate, byte[] additionalData,
+                byte[] publicKey, int signatureAlgorithmId, byte[] signature) {
+            this.v3Digest = v3Digest;
+            this.certificate = certificate;
+            this.additionalData = additionalData;
+            this.publicKey = publicKey;
+            this.signatureAlgorithmId = signatureAlgorithmId;
+            this.signature = signature;
+        }
+
+        /**
+         * Constructs SigningInfo from byte array.
+         */
+        public static SigningInfo fromByteArray(byte[] bytes) throws IOException {
+            ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+            byte[] v3Digest = readBytes(buffer);
+            byte[] certificate = readBytes(buffer);
+            byte[] additionalData = readBytes(buffer);
+            byte[] publicKey = readBytes(buffer);
+            int signatureAlgorithmId = buffer.getInt();
+            byte[] signature = readBytes(buffer);
+            return new SigningInfo(v3Digest, certificate, additionalData, publicKey,
+                    signatureAlgorithmId, signature);
+        }
+    }
+
+    public final int version; // Always 2 for now.
+    public final byte[] hashingInfo;
+    public final byte[] signingInfo; // Passed as-is to the kernel. Can be retrieved later.
 
     /**
      * Construct a V4Signature from .idsig file.
      */
     public static V4Signature readFrom(ParcelFileDescriptor pfd) throws IOException {
-        final ParcelFileDescriptor dupedFd = pfd.dup();
-        final ParcelFileDescriptor.AutoCloseInputStream fdInputStream =
-                new ParcelFileDescriptor.AutoCloseInputStream(dupedFd);
-        try (DataInputStream stream = new DataInputStream(fdInputStream)) {
+        try (InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd.dup())) {
             return readFrom(stream);
         }
     }
 
     /**
-     * Construct a V4Signature from .idsig file.
+     * Construct a V4Signature from a byte array.
      */
     public static V4Signature readFrom(byte[] bytes) throws IOException {
-        try (DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes))) {
+        try (InputStream stream = new ByteArrayInputStream(bytes)) {
             return readFrom(stream);
         }
     }
@@ -63,51 +131,131 @@
      * Store the V4Signature to a byte-array.
      */
     public byte[] toByteArray() {
-        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
-            try (DataOutputStream steam = new DataOutputStream(byteArrayOutputStream)) {
-                this.writeTo(steam);
-                steam.flush();
-            }
-            return byteArrayOutputStream.toByteArray();
+        try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+            this.writeTo(stream);
+            return stream.toByteArray();
         } catch (IOException e) {
             return null;
         }
     }
 
-    boolean isVersionSupported() {
+    /**
+     * Combines necessary data to a signed data blob.
+     * The blob can be validated against signingInfo.signature.
+     *
+     * @param fileSize - size of the signed file (APK)
+     */
+    public static byte[] getSigningData(long fileSize, HashingInfo hashingInfo,
+            SigningInfo signingInfo) {
+        final int size =
+                4/*size*/ + 8/*fileSize*/ + 4/*hash_algorithm*/ + 1/*log2_blocksize*/ + bytesSize(
+                        hashingInfo.salt) + bytesSize(hashingInfo.rawRootHash) + bytesSize(
+                        signingInfo.v3Digest) + bytesSize(signingInfo.certificate) + bytesSize(
+                        signingInfo.additionalData);
+        ByteBuffer buffer = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN);
+        buffer.putInt(size);
+        buffer.putLong(fileSize);
+        buffer.putInt(hashingInfo.hashAlgorithm);
+        buffer.put(hashingInfo.log2BlockSize);
+        writeBytes(buffer, hashingInfo.salt);
+        writeBytes(buffer, hashingInfo.rawRootHash);
+        writeBytes(buffer, signingInfo.v3Digest);
+        writeBytes(buffer, signingInfo.certificate);
+        writeBytes(buffer, signingInfo.additionalData);
+        return buffer.array();
+    }
+
+    public boolean isVersionSupported() {
         return this.version == SUPPORTED_VERSION;
     }
 
-    static V4Signature readFrom(DataInputStream stream) throws IOException {
-        final int version = stream.readInt();
-        byte[] verityRootHash = readBytes(stream);
-        byte[] v3Digest = readBytes(stream);
-        byte[] pkcs7SignatureBlock = readBytes(stream);
-        return new V4Signature(version, verityRootHash, v3Digest, pkcs7SignatureBlock);
-    }
-
-    V4Signature(int version, byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
+    private V4Signature(int version, byte[] hashingInfo, byte[] signingInfo) {
         this.version = version;
-        this.verityRootHash = verityRootHash;
-        this.v3Digest = v3Digest;
-        this.pkcs7SignatureBlock = pkcs7SignatureBlock;
+        this.hashingInfo = hashingInfo;
+        this.signingInfo = signingInfo;
     }
 
-    void writeTo(DataOutputStream stream) throws IOException {
-        stream.writeInt(this.version);
-        writeBytes(stream, this.verityRootHash);
-        writeBytes(stream, this.v3Digest);
-        writeBytes(stream, this.pkcs7SignatureBlock);
+    private static V4Signature readFrom(InputStream stream) throws IOException {
+        final int version = readIntLE(stream);
+        final byte[] hashingInfo = readBytes(stream);
+        final byte[] signingInfo = readBytes(stream);
+        return new V4Signature(version, hashingInfo, signingInfo);
     }
 
-    private static byte[] readBytes(DataInputStream stream) throws IOException {
-        byte[] result = new byte[stream.readInt()];
-        stream.read(result);
-        return result;
+    private void writeTo(OutputStream stream) throws IOException {
+        writeIntLE(stream, this.version);
+        writeBytes(stream, this.hashingInfo);
+        writeBytes(stream, this.signingInfo);
     }
 
-    private static void writeBytes(DataOutputStream stream, byte[] bytes) throws IOException {
-        stream.writeInt(bytes.length);
+    // Utility methods.
+    private static int bytesSize(byte[] bytes) {
+        return 4/*length*/ + (bytes == null ? 0 : bytes.length);
+    }
+
+    private static void readFully(InputStream stream, byte[] buffer) throws IOException {
+        int len = buffer.length;
+        int n = 0;
+        while (n < len) {
+            int count = stream.read(buffer, n, len - n);
+            if (count < 0) {
+                throw new EOFException();
+            }
+            n += count;
+        }
+    }
+
+    private static int readIntLE(InputStream stream) throws IOException {
+        final byte[] buffer = new byte[4];
+        readFully(stream, buffer);
+        return ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
+    }
+
+    private static void writeIntLE(OutputStream stream, int v) throws IOException {
+        final byte[] buffer = ByteBuffer.wrap(new byte[4]).order(ByteOrder.LITTLE_ENDIAN).putInt(
+                v).array();
+        stream.write(buffer);
+    }
+
+    private static byte[] readBytes(InputStream stream) throws IOException {
+        try {
+            final int size = readIntLE(stream);
+            final byte[] bytes = new byte[size];
+            readFully(stream, bytes);
+            return bytes;
+        } catch (EOFException ignored) {
+            return null;
+        }
+    }
+
+    private static byte[] readBytes(ByteBuffer buffer) throws IOException {
+        if (buffer.remaining() < 4) {
+            throw new EOFException();
+        }
+        final int size = buffer.getInt();
+        if (buffer.remaining() < size) {
+            throw new EOFException();
+        }
+        final byte[] bytes = new byte[size];
+        buffer.get(bytes);
+        return bytes;
+    }
+
+    private static void writeBytes(OutputStream stream, byte[] bytes) throws IOException {
+        if (bytes == null) {
+            writeIntLE(stream, 0);
+            return;
+        }
+        writeIntLE(stream, bytes.length);
         stream.write(bytes);
     }
+
+    private static void writeBytes(ByteBuffer buffer, byte[] bytes) {
+        if (bytes == null) {
+            buffer.putInt(0);
+            return;
+        }
+        buffer.putInt(bytes.length);
+        buffer.put(bytes);
+    }
 }
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index a2def7f..f43a252 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -100,10 +100,11 @@
     }
 
     /**
-     * Check if fuse is running in target user, if it's running then setup its obb directories.
-     * TODO: System server should store a list of active pids that obb is not mounted and use it.
+     * Create storage directories if it does not exist.
+     * Return true if the directories were setup correctly, otherwise false.
      */
-    public abstract void prepareObbDirs(int userId, Set<String> packageList, String processName);
+    public abstract boolean prepareStorageDirs(int userId, Set<String> packageList,
+            String processName);
 
     /**
      * Add a listener to listen to reset event in StorageManagerService.
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 0483514..f011395 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -42,6 +42,6 @@
     void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName, String packageName,
                 String permission, int grantState, in AndroidFuture callback);
     void grantOrUpgradeDefaultRuntimePermissions(in AndroidFuture callback);
-    void updateUserSensitive(in AndroidFuture callback);
     void notifyOneTimePermissionSessionTimeout(String packageName);
+    void updateUserSensitiveForApp(int uid, in AndroidFuture callback);
 }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 2615c98..09df72c 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -106,4 +106,12 @@
             int importanceToResetTimer, int importanceToKeepSessionAlive);
 
     void stopOneTimePermissionSession(String packageName, int userId);
+
+    List<String> getAutoRevokeExemptionRequestedPackages(int userId);
+
+    List<String> getAutoRevokeExemptionGrantedPackages(int userId);
+
+    boolean setAutoRevokeWhitelisted(String packageName, boolean whitelisted, int userId);
+
+    boolean isAutoRevokeWhitelisted(String packageName, int userId);
 }
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 2a1857f..f08e3d25 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -46,6 +46,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Process;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -626,14 +627,26 @@
     }
 
     /**
-     * @see PermissionControllerService#onUpdateUserSensitive()
+     * @see PermissionControllerManager#updateUserSensitiveForApp
      * @hide
      */
     public void updateUserSensitive() {
+        updateUserSensitiveForApp(Process.INVALID_UID);
+    }
+
+    /**
+     * @see PermissionControllerService#onUpdateUserSensitiveForApp
+     * @hide
+     */
+    public void updateUserSensitiveForApp(int uid) {
         mRemoteService.postAsync(service -> {
             AndroidFuture<Void> future = new AndroidFuture<>();
-            service.updateUserSensitive(future);
+            service.updateUserSensitiveForApp(uid, future);
             return future;
+        }).whenComplete((res, err) -> {
+            if (err != null) {
+                Log.e(TAG, "Error updating user_sensitive flags for uid " + uid, err);
+            }
         });
     }
 
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 263b2c7..4a42230 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -218,11 +218,14 @@
      * Called by system to update the
      * {@link PackageManager}{@code .FLAG_PERMISSION_USER_SENSITIVE_WHEN_*} flags for permissions.
      * <p>
-     * This is typically when creating a new user or upgrading either system or
-     * permission controller package.
+     *
+     * If uid is -1, updates the permission flags for all packages.
+     *
+     * Typically called by the system when a new app is installed or updated or when creating a
+     * new user or upgrading either system or permission controller package.
      */
     @BinderThread
-    public void onUpdateUserSensitivePermissionFlags() {
+    public void onUpdateUserSensitivePermissionFlags(int uid, @NonNull Runnable callback) {
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
 
@@ -459,11 +462,14 @@
             }
 
             @Override
-            public void updateUserSensitive(AndroidFuture callback) {
+            public void updateUserSensitiveForApp(int uid, @NonNull AndroidFuture callback) {
                 Preconditions.checkNotNull(callback, "callback cannot be null");
 
-                onUpdateUserSensitivePermissionFlags();
-                callback.complete(null);
+                try {
+                    onUpdateUserSensitivePermissionFlags(uid, () -> callback.complete(null));
+                } catch (Exception e) {
+                    callback.completeExceptionally(e);
+                }
             }
 
             @Override
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 0bd211d..8308bb3 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -40,11 +40,13 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.Immutable;
+import com.android.internal.util.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -299,6 +301,46 @@
         }
     }
 
+    /**
+     * Gets the list of packages that have permissions that specified
+     * {@code requestDontAutoRevokePermissions=true} in their
+     * {@code application} manifest declaration.
+     *
+     * @return the list of packages for current user
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY)
+    public Set<String> getAutoRevokeExemptionRequestedPackages() {
+        try {
+            return CollectionUtils.toSet(mPermissionManager.getAutoRevokeExemptionRequestedPackages(
+                    mContext.getUser().getIdentifier()));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the list of packages that have permissions that specified
+     * {@code allowDontAutoRevokePermissions=true} in their
+     * {@code application} manifest declaration.
+     *
+     * @return the list of packages for current user
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY)
+    public Set<String> getAutoRevokeExemptionGrantedPackages() {
+        try {
+            return CollectionUtils.toSet(mPermissionManager.getAutoRevokeExemptionGrantedPackages(
+                    mContext.getUser().getIdentifier()));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList(
             List<SplitPermissionInfoParcelable> parcelableList) {
         final int size = parcelableList.size();
diff --git a/core/java/android/permission/Permissions.md b/core/java/android/permission/Permissions.md
new file mode 100644
index 0000000..e62bd0a
--- /dev/null
+++ b/core/java/android/permission/Permissions.md
@@ -0,0 +1,832 @@
+<!--
+  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
+  -->
+
+# Android permissions for system developers
+
+This document targets system developers. App developers should refer to the [public
+ documentation](https://developer.android.com/guide/topics/permissions/overview).
+
+## Definitions
+
+Each app (often called package) has a unique name called package name. Each package has a manifest
+file describing properties of the package. The android system server is in a special package named
+"android".
+
+When a package gets installed the package is (usually) assigned a unique identifier called [uid
+](../os/Users.md#int-uid).
+This is the same as a uid in Linux, but this often leads to confusion. It is easiest to see a uid
+as a unique identifier for a package.
+
+Usually an app is running in a container called a process. Each process has a unique id called
+pid, but unlike the uid the pid changes each time the process is restarted and app that are not
+currently running don't have a pid. The process container makes sure that other apps cannot
+negatively interact with an app. Processes can only interact via controlled interactions called
+remote procedure calls (RPCs). Android’s RPC mechanism is called _Binder_.
+
+As no app code can be trusted the permission need to be checked on the receiving side of the
+Binder call.
+
+For more details please take a look at [Android's security model](../os/Users.md#security-model).
+
+## Permissions for regular apps
+
+### Install time permissions
+
+The purpose of install time permissions is to control access to APIs where it does not makes sense
+to involve the user. This can be either because the API is not sensitive, or because additional
+checks exist.
+
+#### Defining a permission
+
+Any package can define a permission. For that it simply adds an entry in the manifest file
+`<permission android:name="com.example.myapp.myfirstpermission" />`
+
+Any package can do this, including the system package. When talking about [permissions for system
+ apps](#permissions-for-system-apps) we will see that it is important which package defines a
+permission.
+
+It is common good practice to prefix the permission name with the package name to avoid collisions.
+
+#### Requesting a permission
+
+Any app can request any permission via adding an entry in the manifest file like
+`<uses-permission android:name="com.example.myapp.myfirstpermission" />`
+
+A requested permission does not necessarily mean that the permission is granted. When and how a
+permission is granted depends on the protection level of the permission. If no protection level is
+set, the permission will always be granted. Such "normal" permissions can still be useful as it
+will be easy to find apps using a certain functionality on app stores and by checking `dumpsys
+package`.
+
+#### Checking a permission
+
+`Context.checkPermission(permission, pid, uid)` returns if the pid/uid has the permission. By far
+the most common case is to check the permission on the receiving end of a binder call. In this case
+the pid can be read as `Binder.callingPid()` and the uid as `Binder.callingUid()`. The uid is a
+mandatory argument as permissions are maintained per uid. The pid can be set to -1
+if not pid is available. The context class contains handy wrappers for `checkPermission`, such as
+`enforeCallingPermission` which calls checkPermission with `Binder.callingPid`/`Binder.callingUid`
+and throws a SecurityException when the permission is not granted.
+
+#### Verifying an app has an install time permission
+
+In `dumpsys package my.package.name` there are two sections. In requested permissions all
+permissions of the `uses-permission` tags are listed. In install permission the permissions with
+their grant state are listed. If an install time permission is not listed here, it is not granted.
+
+```
+Packages:
+  Package [com.android.packageinstaller] (2eb7062):
+    userId=10071
+    [...]
+    requested permissions:
+      android.permission.MANAGE_USERS
+      android.permission.INSTALL_PACKAGES
+      android.permission.DELETE_PACKAGES
+      android.permission.READ_INSTALL_SESSIONS
+      android.permission.RECEIVE_BOOT_COMPLETED
+      android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+      android.permission.USE_RESERVED_DISK
+      android.permission.UPDATE_APP_OPS_STATS
+      android.permission.MANAGE_APP_OPS_MODES
+      android.permission.INTERACT_ACROSS_USERS_FULL
+      android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME
+      android.permission.PACKAGE_USAGE_STATS
+    install permissions:
+      android.permission.USE_RESERVED_DISK: granted=true
+      android.permission.INSTALL_PACKAGES: granted=true
+      android.permission.RECEIVE_BOOT_COMPLETED: granted=true
+      android.permission.INTERACT_ACROSS_USERS_FULL: granted=true
+      android.permission.PACKAGE_USAGE_STATS: granted=true
+      android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME: granted=true
+      android.permission.READ_INSTALL_SESSIONS: granted=true
+      android.permission.MANAGE_USERS: granted=true
+      android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS: granted=true
+      android.permission.MANAGE_APP_OPS_MODES: granted=true
+      android.permission.UPDATE_APP_OPS_STATS: granted=true
+      android.permission.DELETE_PACKAGES: granted=true
+```
+
+#### End-to-end: Protecting an RPC call via a permission
+
+##### Service Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.example.myservice">
+    <!-- Define a permission -->
+    <permission android:name="com.android.example.myservice.MY_PERMISSION" />
+    <application>
+        <service android:name=".MyService" android:exported="true" />
+    </application>
+</manifest>
+```
+
+##### Service code
+
+```kotlin
+class MyService : Service() {
+    override fun onBind(intent: Intent?): IBinder? {
+        return object : IMyService.Stub() {
+            override fun doSomething() {
+                // Verify that calling UID has the permission
+                enforceCallingPermission(
+                    "com.android.example.myservice.MY_PERMISSION",
+                    "Need to hold permission"
+                )
+                // do something
+            }
+        }.asBinder()
+    }
+}
+```
+
+##### Caller Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.example.myapp">
+    <!-- request a permission -->
+    <uses-permission android:name="com.android.example.myservice.MY_PERMISSION" />
+    <application />
+</manifest>
+```
+
+### Runtime permissions
+
+Runtime permission must be granted by the user during runtime. This is needed if the API protects
+data or functionality that is sensitive for the user. E.g. the users current location is protected
+by a runtime permission.
+
+Users want a system that is secure and privacy focused by default. User can also often not make a
+good choice when asked at the wrong time without enough context. Hence in general runtime
+permissions should be avoided and the API should be built in a way where no private data needs to be
+leaked.
+
+#### Defining a runtime permission
+
+Runtime permissions are defined in the same way as install time permissions. To tag them as runtime
+permissions the `protectionLevel` needs to be set to dangerous. Dangerous is a synonym for
+runtime permissions in the Android platform.
+
+```xml
+<uses-permission android:name="com.example.myapp.myfirstruntimepermission"
+    android:protectionLevel="dangerous" />
+```
+
+#### Requesting a runtime permission
+
+Similar to install time permissions any app can request a runtime permission by adding the 
+`<uses-permission android:name="com.example.myapp.myfirstruntimepermission" />`
+to the manifest.
+
+By default runtime permissions are not granted. The app needs to call `Activity.requestPermissions`
+during runtime to ask the user for the permission. The user might then grant or deny and once the
+decision is made the activity is called by via `Activity.onPermissionGranted`.
+
+During development and testing a runtime permission can be granted via the `pm` shell command or by
+using the `UiAutomator.grantRuntimePermission` API call. Please note that this does _not_ grant the
+[app-op](#runtime-permissions-and-app-ops) synchronously. Unless the app needs to test the actual
+permission grant flow it is recommended to grant the runtime permissions during install using
+`adb install -g /my/package.apk`.
+
+#### Checking a runtime permission
+
+For runtime permissions defined by a 3rd party apps it is fine to check a runtime
+permission like an install time permission. For system defined permissions you need to check all
+runtime permissions by using the `PermissionChecker` utility. It is good practice to use the tool
+anywhere possible.
+
+The permission checker might return `PERMISSION_DENIED_APP_OP` which should lead to a silent
+failure. This can only happen for system defined runtime permissions.
+
+##### Runtime permissions and app-ops
+
+> See [App-ops](../app/AppOps.md).
+
+The PermissionChecker code fundamentally looks like this:
+
+```kotlin
+class PermissionChecker {
+    fun checkCallingPermission(context: Context, permission: String) {
+        if (isRuntimePermission(permission)) {
+            if (context.checkPermission(uid, permission) == DENIED) {
+                 return PERMISSION_DENIED
+            }
+
+            val appOpOfPermission = AppOpsManager.permissionToOp(permission)
+            if (appOpOfPermission == null) {
+                // not platform defined
+                return PERMISSION_GRANTED
+            }
+
+            val appOpMode = appOpsManager.noteOp(appOpOfPermission)
+            if (appOpMode == AppOpsManager.MODE_ALLOWED) {
+                return PERMISSION_GRANTED
+            } else {
+                return PERMISSION_DENIED_APP_OP
+            }
+        } else {
+            return PERMISSION_DENIED
+        }
+    }
+}
+```
+
+For each platform defined runtime permission there is a matching app-op. When calling
+`AppOpsManager.noteOp` this returns either `MODE_ALLOWED` or `MODE_IGNORED`.
+
+This value is then used to decide between `PERMISSION_DENIED_APP_OP` and `PERMISSION_GRANTED`.
+
+The primary purpose of the special `PERMISSION_DENIED_APP_OP` state was to support apps targeting an
+SDK lower than 23. These apps do not understand the concept of denied runtime permissions. Hence
+they would crash when getting a `SecurityException`. To protect the users' privacy while still not
+crashing the app the special `PERMISSION_DENIED_APP_OP` mandates that the API should somehow
+silently fail.
+
+A secondary use case of the `AppOpsManager.noteOp` calls is to
+[track](../app/AppOps.md#Appops-for-tracking) which apps perform what runtime protected actions.
+
+#### Verifying an app has a runtime time permission
+
+In `dumpsys package my.package.name` the runtime permissions are listed per uid. I.e. different
+users might have different runtime permission grants and shared uids share a grant-set. If a runtime
+permission is listed as requested but not in the runtime permission section it is in it’s initial
+state, i.e. not granted.
+
+```
+Packages:
+  Package [com.google.android.GoogleCamera] (ccb6af):
+    userId=10181
+    [...]
+    requested permissions:
+      android.permission.ACCESS_COARSE_LOCATION
+      android.permission.ACCESS_FINE_LOCATION
+      android.permission.ACCESS_NETWORK_STATE
+      android.permission.ACCESS_NOTIFICATION_POLICY
+      android.permission.ACCESS_WIFI_STATE
+      android.permission.BIND_WALLPAPER
+      android.permission.CAMERA
+      android.permission.CHANGE_WIFI_STATE
+      android.permission.INTERNET
+      android.permission.GET_PACKAGE_SIZE
+      android.permission.NFC
+      android.permission.READ_SYNC_SETTINGS
+      android.permission.RECEIVE_BOOT_COMPLETED
+      android.permission.RECORD_AUDIO
+      android.permission.SET_WALLPAPER
+      android.permission.USE_CREDENTIALS
+      android.permission.VIBRATE
+      android.permission.WAKE_LOCK
+      android.permission.WRITE_EXTERNAL_STORAGE [ ... ]
+      android.permission.WRITE_SETTINGS
+      android.permission.WRITE_SYNC_SETTINGS
+      com.google.android.elmyra.permission.CONFIGURE_ASSIST_GESTURE
+      com.google.android.providers.gsf.permission.READ_GSERVICES
+      android.permission.FOREGROUND_SERVICE
+      com.google.android.googlequicksearchbox.permission.LENSVIEW_BROADCAST
+      android.permission.READ_EXTERNAL_STORAGE [ ... ]
+    [...]
+    User 0: [ ... ]
+    overlay paths:
+      runtime permissions:
+        android.permission.ACCESS_FINE_LOCATION: granted=false [ ... ]
+        android.permission.READ_EXTERNAL_STORAGE: granted=true [ ... ]
+        android.permission.ACCESS_COARSE_LOCATION: granted=false [ ... ]
+        android.permission.CAMERA: granted=true [ ... ]
+        android.permission.WRITE_EXTERNAL_STORAGE: granted=true [ ... ]
+        android.permission.RECORD_AUDIO: granted=true[ ... ]
+```
+
+#### End-to-end: Protecting an RPC call via a runtime permission
+
+##### Service Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.example.myservice">
+    <!-- Define a runtime permission -->
+    <permission android:name="com.android.example.myservice.MY_RUNTIME_PERMISSION"
+        android:protectionLevel="dangerous" />
+    <application>
+        <service android:name=".MyService" android:exported="true" />
+    </application>
+</manifest>
+```
+
+##### Service code
+
+```kotlin
+class MyService : Service() {
+    override fun onBind(intent: Intent?): IBinder? {
+        return object : IMyService.Stub() {
+            override fun doSomething(callingPackage: String?, callingFeatureId: String?) {
+                Objects.requireNonNull(callingPackageName)
+
+                // Verify that calling UID has the permission
+                when (run {
+                    PermissionChecker.checkCallingPermission(
+                        this@MyService,
+                         "com.android.example.myservice.MY_RUNTIME_PERMISSION",
+                        callingPackageName,
+                        callingFeatureId,
+                        "Did something"
+                    )
+                }) {
+                    PERMISSION_GRANTED -> /* do something */
+                    PERMISSION_DENIED_APP_OP -> /* silent failure, do nothing */
+                    else -> throw SecurityException(
+                        "Cannot do something as caller is missing "
+                                + "com.android.example.myservice.MY_RUNTIME_PERMISSION"
+                    )
+                }
+            }
+        }.asBinder()
+    }
+}
+```
+
+##### Caller Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.example.myapp">
+    <!-- request a permission -->
+    <uses-permission android:name="com.android.example.myservice.MY_RUNTIME_PERMISSION" />
+    <application />
+</manifest>
+```
+
+##### Caller code
+
+```kotlin
+class MyActivity : Activity {
+    fun callDoSomething() {
+        if (checkSelfPermission("com.android.example.myservice.MY_RUNTIME_PERMISSION") == PERMISSION_DENIED) {
+            // Interrupt operation and request permission
+            requestPermissions(arrayOf("com.android.example.myservice.MY_RUNTIME_PERMISSION"), 23)
+        } else {
+            myService.doSomething(this@MyActivity.opPackageName, this@MyActivity.featureId)
+        }
+    }
+
+    override fun onRequestPermissionsResult(
+        requestCode: Int,
+        permissions: Array<String>,
+        grantResults: IntArray
+    ) {
+        if (requestCode == 23 && grantResults[0] == PERMISSION_GRANTED) {
+            // Finish operation
+            callDoSomething()
+        }
+    }
+}
+```
+
+#### Restricted permissions
+
+Some runtime permissions are restricted. They are annotated in the platforms `AndroidManifest.xml`
+has `hardRestricted` or `softRestricted`.
+
+Restricted permissions behave uncommon when not whitelisted. When whitelisted the permissions
+behave normally. What uncommon means depends on the whether they are hard or soft restricted.
+
+They can either be whitelisted during upgrade P->Q, but the system or need to be whitelisted by the
+installer via `PackageInstaller.SessionParams.setWhitelistedRestrictedPermissions`. If this method
+is not used all permissions will be whitelisted.
+
+Afterwards the app that originally installed the app can change the whitelisting state via
+`PackageManager.addWhitelistedRestrictedPermission` and
+`PackageManager.removeWhitelistedRestrictedPermission`.
+
+The system tracks the source of the whitelisting by having three different flags
+ `RESTRICTION_SYSTEM_EXEMPT`, `RESTRICTION_UPGRADE_EXEMPT`, and `RESTRICTION_INSTALLER_EXEMPT`,
+
+The flags can be checked in `dumpsys package my.package.name`
+
+```
+User 0:
+  [...]
+  runtime permissions:
+    android.permission.READ_EXTERNAL_STORAGE: granted=false, flags=[ RESTRICTION_UPGRADE_EXEMPT ]
+    android.permission.ACCESS_FINE_LOCATION: granted=true, flags=[ RESTRICTION_SYSTEM_EXEMPT|RESTRICTION_UPGRADE_EXEMPT ]
+```
+
+##### Hard restricted
+
+Hard restricted permissions need to be whitelisted to be grant-able.
+
+##### Soft restricted
+
+The behavior of non-whitelisted soft restricted permissions is not uniform. The behavior is
+defined in the `SoftRestrictedPermissionPolicy`.
+
+#### System fixed permission
+
+Some runtime permissions are required for normal operation of the device. In this case the system
+can grant the permission as `SYSTEM_FIXED`. In this case the permission can be seen in the
+[permission management settings](#settings) but cannot be revoked by the user.
+
+The flag can be checked in `dumpsys package my.package.name`
+```
+User 0:
+  [...]
+  runtime permissions:
+    android.permission.READ_EXTERNAL_STORAGE: granted=true, flags=[ SYSTEM_FIXED|GRANTED_BY_DEFAULT ]
+```
+
+#### Background access
+
+Whether the app is currently visible to the user is reflected in the `ActivityManager`'s proc state.
+There is a lot of granularity to this, but runtime permissions are using the [app-ops services'
+](../app/AppOps.md) definition of foreground and background.
+
+Most runtime permissions are not affected by foreground/background-ness. Microphone and Camera are
+foreground-only while Location is usually foreground-only, but background access can be added by
+granting the `ACCESS_BACKGROUND_LOCATION` modifier runtime permission.
+
+##### Microphone and Camera
+
+Currently these only allow access while in the app is in foreground. There is a manual whitelist
+for e.g. the voice interaction service.
+
+This is currently (Mar 2020) reworked and will behave like [location](#location) soon.
+
+##### Location
+
+As described [above](#runtime-permissions-and-app-ops) the app-op mode for granted permissions is
+`MODE_ALLOWED` to allow access or `MODE_IGNORED` to suppress access.
+
+The important case is the case where the permission is granted and the app-op is `MODE_IGNORED`. In
+the case of location this state causes the `LocationManagerService` to stop delivering locations to
+the app. This is not a breaking behavior as the same scenarios happens if e.g. no satellites
+could be found.
+
+This behavior is used to implement the foregound/background behavior for location. If the app is
+in the foreground the app-op mode is `MODE_ALLOWED` and works normally. If the app goes into
+background the app-op mode changes to `MODE_IGNORED`. This means that locations are delivered while
+the app is in foreground and while the app is background, the app won't get any locations.
+
+The automatic switching between `MODE_ALLOWED` and `MODE_IGNORED` is done inside of
+ [`AppOpsManager`](../app/AppOps.md#foreground).
+
+Background access can be enabled by also granting the `ACCESS_BACKGROUND_LOCATION` to the app. In
+this case the app-op mode will always be `MODE_ALLOWED`.
+
+#### UI
+
+##### Granting
+
+An app following the best practices does not ask for any runtime permissions until absolutely
+needed. Once needed the request should be made in context. I.e. the user should understand from the
+current state of the app and the user's action why the request is made. E.g. if the user presses
+a "show me the next ATM"-button the user is most likely expecting a request for the location
+permission.
+
+This is central premise to the runtime permission UI. It is the app's responsibility to avoid
+showing permission requests dialogs to the user which might get denied. These dialogs are not
+meant to be user-choices, they are meant to be user-confirmations.
+
+Hence any denied permission dialog is probably due to the app asking for permissions the user
+does not expect. If too many permission requests get denied the app is apparently trying to get
+more than the user wants to give to the app. In this case the permission gets permanently denied
+and all future requests will be denied automatically without showing a UI.
+
+`Context.requestPermission` calls for more than one permission are allowed and might result in
+multiple dialogs in sequence. This might make sense for e.g. getting microphone and camera
+permission when starting a video call.
+
+Each time the the user makes a choice (either to grant or the deny) a permission request the
+permission is marked as `USER_SET`. If a permission gets permanently denied the permission is marked
+as `USER_FIXED`.
+
+This can be found in `dumpsys package my.package.name`
+```
+User 0:
+  [...]
+  runtime permissions:
+    android.permission.READ_EXTERNAL_STORAGE: granted=false, flags=[ USER_SET|USER_FIXED ]
+    android.permission.ACCESS_FINE_LOCATION: granted=true, flags=[ USER_SET ]
+```
+
+##### Settings
+
+By far most interactions with the permission system are via the [permission grant flow](#granting).
+The main purpose of the permission settings is to show the user the previous choices and allow
+the user to revisit previous choices. In reality few users do that.
+
+##### Grouping
+
+There are too many runtime permissions for the user to individually manage. Hence the UI bundles the
+permissions into groups. **Apps should never assume the grouping**. The grouping might change
+with SDK updates, but also at any other time. Certain form factors or locales might use other
+permission models and sometimes some of the permissions of a group cannot be granted for various
+reasons. The grouping is defined inside the permission controller app.
+
+If two permissions belong to a group and the first permission is already granted the second one
+will be granted on request of the app without user interaction. For that reason a permission
+group with at least one individual permission granted will show up as granted in the UI.
+
+##### Alternate permission management
+
+It is not allowed to build alternate permission management UIs. While restricting innovation is not
+a good choice this is a required one to enforce a consistent, predictable, but flexible permission
+model for users and app developers.
+
+Further some data needed for permission management (e.g. the grouping) is not available outside
+the permission controller app.
+
+Hence all permission management UI needs to be integrated with AOSP.
+
+#### Pre granting
+
+Runtime permissions protect user private data. It is a violation of user trust to give the data
+to an app without explicit user consent (i.e. the user [granting](#granting) the permission
+). Still the user expects certain functionality (e.g. receiving a phone call) to work out of the
+box.
+
+Hence the `DefaultPermissionGrantPolicy` and roles allow to grant permission without the user
+. The default permission grant policy grants permissions for three categories of apps
+- Apps running in well defined [uids](../os/Users.md#int-uid) as they are considered as part of
+ the platform
+- Apps that are in certain predefined categories, e.g. the browser and the SMS app. This is
+ meant for the most basic phone functionality, not for all pre-installed apps.
+- Apps that are explicitly mentioned as a pre-grant-exceptions. This is meant to be used for setup
+ and other highly critical use cases, not to improve the user experience. The exceptions are listed
+ in xml files in `etc/` and follow the following syntax
+```xml
+<exceptions>
+    <exception package="my.package.name">
+        <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false"/>
+    </exception>
+</exceptions>
+```
+
+Pre-granted runtime permissions can still be revoked by the user in [settings](#settings) unless
+they are granted as `SYSTEM_FIXED`.
+
+Whether a permission was granted by the default can be checked in the permission flags of
+`dumpsys package my.package.name`
+
+```
+User 0:
+  [...]
+  runtime permissions:
+    android.permission.ACCESS_FINE_LOCATION: granted=true, flags=[ GRANTED_BY_DEFAULT ]
+```
+
+### Permission restricted components
+
+As [publicly documented](https://developer.android.com/guide/topics/permissions/overview#permission_enforcement)
+it is possible to restrict starting an activity/binding to a service by using permission. It is
+a common pattern to
+
+- define a permission in the platform as `signature`
+- protect a service in an app by this permission using the `android:permission` attribute of the
+ `<service>` tag
+
+Then it is guaranteed that only the system can bind to such service. This is used for services
+that provide extensions to platform functionality, such as auto-fill services, print services, and
+accessibility services.
+
+This does not work for app-op or runtime permissions as the way to check these permissions is
+more complex than install time permissions.
+
+## Permissions for system apps
+
+System apps need to integrate deeper with the system than regular apps. Hence they need to be
+able to call APIs not available to other apps. This is implemented by granting permissions to
+these system apps and then enforcing the permissions in the API similar to other [install time
+permissions](#checking-a-permission).
+
+System apps are not different from regular apps, but the protection levels (e.g.
+[privileged](#privileged-permissions), [preinstalled](#preinstalled-permissions)) mentioned in this
+section are more commonly used by system apps.
+
+### Multiple permission levels
+
+It is possible to assign multiple protection levels to a permission. Very common combinations are
+for example adding `signature` to all permissions to make sure the platform signed apps can be
+granted the permission, e.g. `privileged|signature`.
+
+The permission will be granted if the app qualifies for _any_ of the permission levels.
+
+### App-op permissions
+
+> See [App-ops](../app/AppOps.md).
+
+App-op permissions are user-switchable permissions that are not runtime permissions. This should
+be used for permissions that are really only meant to be ever granted to a very small amount of
+apps. Traditionally granting these permissions is intentionally very heavy weight so that the
+user really needs to understand the use case. For example one use case is the
+`INTERACT_ACROSS_PROFILES` permission that allows apps of different
+[user profiles](../os/Users.md#user-profile) to interact. Of course this is breaking a very basic
+security container and hence should only every be granted with a lot of care.
+
+**Warning:** Most app-op permissions follow this logic, but most of them also have exceptions
+and special behavior. Hence this section is a guideline, not a rule.
+
+#### Defining an app-op permission
+
+Only the platform can reasonably define an app-op permission. The permission is defined in the
+platforms manifest using the `appop` protection level
+
+```xml
+<manifest package="android">
+    <permission android:name="android.permission.MY_APPOP_PERMISSION"
+        android:protectionLevel="appop|signature" />
+</manifest>
+```
+
+Almost always the protection level is app-op | something else, like
+[signature](#signature-permissions) (in the case above) or [privileged](#privileged-permissions).
+
+#### Checking a app-op permission
+
+The `PermissionChecker` utility can check app-op permissions with the [same syntax as runtime
+permissions](#checking-a-runtime-permission).
+
+The permission checker internally follows this flow
+
+```kotlin
+class PermissionChecker {
+    fun checkCallingPermission(context: Context, permission: String) {
+        if (isAppOpPermission(permission)) {
+            val appopOfPermission = AppOpsManager.permissionToOp(permission)
+            if (appopOfPermission == null) {
+                // not platform defined
+                return PERMISSION_DENIED
+            }
+
+            val appopMode = appOpsManager.noteOp(appopOfPermission)
+            when (appopMode) {
+                AppOpsManager.MODE_ALLOWED -> return PERMISSION_GRANTED
+                AppOpsManager.MODE_IGNORED -> return PERMISSION_DENIED
+                AppOpsManager.MODE_DEFAULT -> {
+                    if (context.checkPermission(uid, permission) == GRANTED) {
+                        return PERMISSION_GRANTED
+                    } else {
+                        return PERMISSION_DENIED
+                    }
+                }
+            }
+        } else {
+            return PERMISSION_DENIED
+        }
+    }
+}
+```
+
+#### Granting a app-op permission
+
+The permission's grant state is only considered if the app-op's mode is `MODE_DEFAULT`. This
+allows to have default grants while still being overridden by the app-op.
+
+The permission is then granted by setting the app-op mode. This is usually done via dedicated APIs
+for each use cases. Similarly whether and how an app can request the permission is different for
+each app-op permission.
+
+When implementing a new app-op permission, make sure to set the app-op mode using `AppOpsManager
+.setUidMode` to make sure the permission is granted on the uid as this is the security domain.
+
+During development app-ops can be grated to app via the `appops set` shell command. E.g.
+
+```
+adb shell appops set 10187 INTERACT_ACROSS_PROFILES allow
+```
+
+sets the `INTERACT_ACROSS_PROFILES` app-op for uid 10187 to allow thereby granting apps in this
+uid the ability to interact across profiles.
+
+##### UI
+
+Most UIs for app-op permissions are in the "Special app access" section of the settings app.
+
+In most cases the permission should only be granted with the user's explicit agreement, usually by
+allowing the app to directly open the "Special app access" page for this permission and app.
+
+To repeat: this is a guideline for app-op permissions and there are many exceptions.
+
+### Signature permissions
+
+Only apps signed with the defining app's certificate will be granted the permission. This is
+used to restrict APIs to apps of the same developer.
+
+This is frequently used to restrict permissions defined by the platform to apps also signed with
+the platform's certificate. As this is a very tight restriction this is recommended for
+permissions that are only used by apps built out of AOSP which are signed with the platform
+certificate.
+
+Please note that OEMs sign their platform them self. I.e. OEMs can implement new apps using these
+permissions. It is unlikely that 3rd party apps will be able to use APIs protected by signature
+permissions as they are usually not signed with the platform certificate.
+
+Such permissions are defined and checked like an install time permission.
+
+### Preinstalled permissions
+
+This means that the app has to be pre-installed. There is no restriction what apps are pre-installed
+on a particular device install there. Hence it can be really any app including 3rd party apps.
+
+Hence this permission level is discouraged unless there are
+[further restrictions](#restricted-by-tests).
+
+Such permissions are defined and checked like an install time permission.
+
+### Privileged permissions
+
+This means that the app has to be pre-installed and in the `system/priv` directory in the
+filesystem. There is no restriction what apps are in this directory on a particular device
+install there. Hence it can be really any app including 3rd party apps.
+
+An app is only ever granted privileged permissions requested by the pre-installed apk. I.e.
+privileged permissions added in updates will never be granted.
+
+Hence this permission level is discouraged unless there are
+[further restrictions](#restricted-by-tests).
+
+Such permissions are defined and checked like an install time permission.
+
+#### Restricted by tests
+
+As all apps that might get preinstalled or privilidged permissions need to be pre-installed and new
+images need to pass compliance tests it is possible to use a test to whitelist the apps that can
+request the permission.
+
+Example of such a test:
+```kotlin
+/* Add new whitelisted packages to this list */
+private val whitelistedPkgs = listOf("my.whitelisted.package")
+
+@Test
+fun onlySomeAppsAreAllowedToHavePermissionGranted() {
+    assertThat(whitelistedPkgs).containsAllIn(
+            context.packageManager.getInstalledPackages(MATCH_ALL)
+                    .filter { pkg ->
+                        context.checkPermission(android.Manifest.permission.MY_PRIVILEGED_PERMISSION, -1,
+                                pkg.applicationInfo.uid) == PERMISSION_GRANTED
+                    /* The permission is defined by the system and hence granted to it */
+                    }.filter { pkg -> pkg.applicationInfo.uid != SYSTEM_UID }
+                    .map { it.packageName }
+    )
+}
+```
+
+#### Whitelist
+
+As mentioned above it is not suggested, but still common practice to install 3rd party apps as
+privilidged. To verify and restrict which privilidged permissions those apps get granted all
+privilidged permissions need to be explicitly whitelisted in a file `/etc`.
+
+```xml
+<permissions>
+    <privapp-permissions package="my.privileged.package">
+        <!-- allow the app to request a permission -->
+        <permission name="android.permission.MY_PRIVILEGED_PERMISSION"/>
+
+        <!-- Even though the app requests the permission, do not grant it -->
+        <deny-permission name="android.permission.MY_OTHER_PRIVILEGED_PERMISSION"/>
+    </privapp-permissions>
+</permissions>
+```
+
+If the pre-installed apk of app requests a privileged permission that is not mentioned in any
+whitelist or that is not denied the system will refuse to boot. As mentioned above privileged
+permissions added in updates to the pre-installed app will never be granted.
+
+### Limited permissions
+
+E.g. installer, wellbeing, documenter, etc... This allows the system to restrict the permission to a
+well defined app or set of apps. It is possible to add new types in `PackageManagerService`.
+
+Which apps qualify for such a permission level is flexible and custom for each such level. Usually
+they refer to a single or small set of apps, usually - but not always - apps defined in AOSP.
+
+These permissions are defined and checked like an install time permission.
+
+### Development permissions
+
+> Not recommended
+
+By adding the `development` protection level to any permissions the permission can be granted via
+the `pm grant` shell command. This appears to be useful for development and testing, but it is very
+highly discouraged. Any user can grant them permanently via adb, hence adding this tag removes
+all guarantees the permission might otherwise provide.
+
+### Other protection levels
+
+There are other levels (such as `runtime`) but they are for special purposes on should not be
+used by platform developers.
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index aa511cc..fb81d67 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -399,6 +399,13 @@
     public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER =
             "connectivity_thermal_power_manager";
 
+    /**
+     * Namespace for configuration related features.
+     *
+     * @hide
+     */
+    public static final String NAMESPACE_CONFIGURATION = "configuration";
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index a80153d..327bca2 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -1081,7 +1081,7 @@
             // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
             // MANAGE_DOCUMENTS or associated URI permission here instead
             final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
-            enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingFeatureId(),
+            enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingAttributionTag(),
                     null);
 
             final String rootId = DocumentsContract.getRootId(rootUri);
@@ -1103,8 +1103,8 @@
         enforceTree(documentUri);
 
         if (METHOD_IS_CHILD_DOCUMENT.equals(method)) {
-            enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
+            enforceReadPermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
 
             final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String childAuthority = childUri.getAuthority();
@@ -1116,8 +1116,8 @@
                             && isChildDocument(documentId, childId));
 
         } else if (METHOD_CREATE_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
 
             final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
             final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -1131,8 +1131,8 @@
             out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
         } else if (METHOD_CREATE_WEB_LINK_INTENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
 
             final Bundle options = extras.getBundle(DocumentsContract.EXTRA_OPTIONS);
             final IntentSender intentSender = createWebLinkIntent(documentId, options);
@@ -1140,8 +1140,8 @@
             out.putParcelable(DocumentsContract.EXTRA_RESULT, intentSender);
 
         } else if (METHOD_RENAME_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
 
             final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
             final String newDocumentId = renameDocument(documentId, displayName);
@@ -1165,8 +1165,8 @@
             }
 
         } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
             deleteDocument(documentId);
 
             // Document no longer exists, clean up any grants.
@@ -1176,9 +1176,9 @@
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
-            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+            enforceReadPermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
+            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingAttributionTag(),
                     null);
 
             final String newDocumentId = copyDocument(documentId, targetId);
@@ -1202,11 +1202,11 @@
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
-            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
-            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+            enforceWritePermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
+            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingAttributionTag(),
                     null);
 
             final String newDocumentId = moveDocument(documentId, parentSourceId, targetId);
@@ -1228,10 +1228,10 @@
             final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
             final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
 
-            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
-            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                    null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(),
+                    getCallingAttributionTag(), null);
             removeDocument(documentId, parentSourceId);
 
             // It's responsibility of the provider to revoke any grants, as the document may be
@@ -1240,8 +1240,8 @@
             final boolean isTreeUri = isTreeUri(documentUri);
 
             if (isTreeUri) {
-                enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
-                        null);
+                enforceReadPermissionInner(documentUri, getCallingPackage(),
+                        getCallingAttributionTag(), null);
             } else {
                 getContext().enforceCallingPermission(Manifest.permission.MANAGE_DOCUMENTS, null);
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23c074c..d8679b20 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2624,7 +2624,7 @@
                     arg.putBoolean(CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
                 }
                 IContentProvider cp = mProviderHolder.getProvider(cr);
-                cp.call(cr.getPackageName(), cr.getFeatureId(),
+                cp.call(cr.getPackageName(), cr.getAttributionTag(),
                         mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
@@ -2644,7 +2644,7 @@
                 args.putString(CALL_METHOD_PREFIX_KEY, prefix);
                 args.putSerializable(CALL_METHOD_FLAGS_KEY, keyValues);
                 IContentProvider cp = mProviderHolder.getProvider(cr);
-                Bundle bundle = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                Bundle bundle = cp.call(cr.getPackageName(), cr.getAttributionTag(),
                         mProviderHolder.mUri.getAuthority(),
                         mCallSetAllCommand, null, args);
                 return bundle.getBoolean(KEY_CONFIG_SET_RETURN);
@@ -2719,14 +2719,14 @@
                     if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                         final long token = Binder.clearCallingIdentity();
                         try {
-                            b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                            b = cp.call(cr.getPackageName(), cr.getAttributionTag(),
                                     mProviderHolder.mUri.getAuthority(), mCallGetCommand, name,
                                     args);
                         } finally {
                             Binder.restoreCallingIdentity(token);
                         }
                     } else {
-                        b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                        b = cp.call(cr.getPackageName(), cr.getAttributionTag(),
                                 mProviderHolder.mUri.getAuthority(), mCallGetCommand, name, args);
                     }
                     if (b != null) {
@@ -2796,13 +2796,13 @@
                 if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                     final long token = Binder.clearCallingIdentity();
                     try {
-                        c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+                        c = cp.query(cr.getPackageName(), cr.getAttributionTag(), mUri,
                                 SELECT_VALUE_PROJECTION, queryArgs, null);
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
                 } else {
-                    c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+                    c = cp.query(cr.getPackageName(), cr.getAttributionTag(), mUri,
                             SELECT_VALUE_PROJECTION, queryArgs, null);
                 }
                 if (c == null) {
@@ -2895,7 +2895,7 @@
                 }
 
                 // Fetch all flags for the namespace at once for caching purposes
-                Bundle b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                Bundle b = cp.call(cr.getPackageName(), cr.getAttributionTag(),
                         mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
                 if (b == null) {
                     // Invalid response, return an empty map
@@ -5540,7 +5540,7 @@
                 }
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
                         sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SECURE, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
@@ -6090,10 +6090,7 @@
          * device is removed from this mode.
          * <p>
          * Type: int (0 for false, 1 for true)
-         *
-         * @hide
          */
-        @SystemApi
         public static final String SECURE_FRP_MODE = "secure_frp_mode";
 
         /**
@@ -8500,7 +8497,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
 
         /**
@@ -13386,7 +13382,7 @@
                 }
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
                         sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_GLOBAL, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
@@ -14361,7 +14357,7 @@
                     arg.putString(Settings.CALL_METHOD_PREFIX_KEY, createPrefix(namespace));
                 }
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
                         sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_CONFIG, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset to defaults for " + DeviceConfig.CONTENT_URI, e);
@@ -14390,7 +14386,7 @@
                 arg.putInt(CALL_METHOD_USER_KEY, userHandle);
                 arg.putParcelable(CALL_METHOD_MONITOR_CALLBACK_KEY, callback);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
                         sProviderHolder.mUri.getAuthority(),
                         CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG, null, arg);
             } catch (RemoteException e) {
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 03b38ab..e7b360d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3551,7 +3551,6 @@
          * can manage DPC-owned APNs.
          * @hide
          */
-        @SystemApi
         public static final @NonNull Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
 
         /**
@@ -3864,7 +3863,6 @@
          * Integer value denoting an invalid APN id
          * @hide
          */
-        @SystemApi
         public static final int INVALID_APN_ID = -1;
 
         /**
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 886b433..08aa534 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -232,22 +232,6 @@
          * Creates a new builder.
          *
          * @param presentation The presentation used to visualize this dataset.
-         * @param inlinePresentation The {@link InlinePresentation} used to visualize this dataset
-         *              as inline suggestions. If the dataset supports inline suggestions,
-         *              this should not be null.
-         */
-        public Builder(@NonNull RemoteViews presentation,
-                @NonNull InlinePresentation inlinePresentation) {
-            Preconditions.checkNotNull(presentation, "presentation must be non-null");
-            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null");
-            mPresentation = presentation;
-            mInlinePresentation = inlinePresentation;
-        }
-
-        /**
-         * Creates a new builder.
-         *
-         * @param presentation The presentation used to visualize this dataset.
          */
         public Builder(@NonNull RemoteViews presentation) {
             Preconditions.checkNotNull(presentation, "presentation must be non-null");
@@ -282,6 +266,22 @@
         }
 
         /**
+         * Sets the {@link InlinePresentation} used to visualize this dataset as inline suggestions.
+         * If the dataset supports inline suggestions this should not be null.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
+         *
+         * @return this builder.
+         */
+        public @NonNull Builder setInlinePresentation(
+                @NonNull InlinePresentation inlinePresentation) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null");
+            mInlinePresentation = inlinePresentation;
+            return this;
+        }
+
+        /**
          * Triggers a custom UI before before autofilling the screen with the contents of this
          * dataset.
          *
@@ -600,7 +600,7 @@
          */
         @SystemApi
         @TestApi
-        public @NonNull Builder setInlinePresentation(@NonNull AutofillId id,
+        public @NonNull Builder setFieldInlinePresentation(@NonNull AutofillId id,
                 @Nullable AutofillValue value, @Nullable Pattern filter,
                 @NonNull InlinePresentation inlinePresentation) {
             throwIfDestroyed();
@@ -700,7 +700,7 @@
             final Builder builder = presentation != null
                     ? inlinePresentation == null
                             ? new Builder(presentation)
-                            : new Builder(presentation, inlinePresentation)
+                            : new Builder(presentation).setInlinePresentation(inlinePresentation)
                     : inlinePresentation == null
                             ? new Builder()
                             : new Builder(inlinePresentation);
diff --git a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
index 1011651..1bcc76b 100644
--- a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
+++ b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
@@ -25,7 +25,8 @@
  * @hide
  */
 oneway interface IInlineSuggestionUiCallback {
-    void onAutofill();
+    void onClick();
+    void onLongClick();
     void onContent(in SurfaceControlViewHost.SurfacePackage surface);
     void onError();
     void onTransferTouchFocusToImeWindow(in IBinder sourceInputToken, int displayId);
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index ee152837..f0a72c5 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -94,15 +94,24 @@
 
             final SurfaceControlViewHost host = new SurfaceControlViewHost(this, getDisplay(),
                     hostInputToken);
-            host.addView(suggestionRoot, lp);
+            host.setView(suggestionRoot, lp);
             suggestionRoot.setOnClickListener((v) -> {
                 try {
-                    callback.onAutofill();
+                    callback.onClick();
                 } catch (RemoteException e) {
-                    Log.w(TAG, "RemoteException calling onAutofill()");
+                    Log.w(TAG, "RemoteException calling onClick()");
                 }
             });
 
+            suggestionRoot.setOnLongClickListener((v) -> {
+                try {
+                    callback.onLongClick();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException calling onLongClick()");
+                }
+                return true;
+            });
+
             sendResult(callback, host.getSurfacePackage());
         } finally {
             updateDisplay(Display.DEFAULT_DISPLAY);
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index ed27dd5..5b08ae20 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -488,7 +488,8 @@
                 ids.add(pair.first);
                 values.add(pair.second);
             }
-            mClient.autofill(mSessionId, ids, values);
+            final boolean hideHighlight = size == 1 && ids.get(0).equals(mFocusedId);
+            mClient.autofill(mSessionId, ids, values, hideHighlight);
         }
 
         public void setFillWindow(@NonNull FillWindow fillWindow) {
diff --git a/core/java/android/service/quickaccesswallet/GetWalletCardsCallbackImpl.java b/core/java/android/service/quickaccesswallet/GetWalletCardsCallbackImpl.java
index d2494a5..ae67068 100644
--- a/core/java/android/service/quickaccesswallet/GetWalletCardsCallbackImpl.java
+++ b/core/java/android/service/quickaccesswallet/GetWalletCardsCallbackImpl.java
@@ -24,8 +24,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.List;
-
 /**
  * Handles response from the {@link QuickAccessWalletService} for {@link GetWalletCardsRequest}
  *
@@ -56,7 +54,6 @@
      *                 presented as the selected card.
      */
     public void onSuccess(@NonNull GetWalletCardsResponse response) {
-        Log.i(TAG, "onSuccess");
         if (isValidResponse(response)) {
             mHandler.post(() -> onSuccessInternal(response));
         } else {
@@ -78,7 +75,6 @@
     }
 
     private void onSuccessInternal(GetWalletCardsResponse response) {
-        Log.i(TAG, "onSuccessInternal");
         if (mCalled) {
             Log.w(TAG, "already called");
             return;
@@ -86,7 +82,6 @@
         mCalled = true;
         try {
             mCallback.onGetWalletCardsSuccess(response);
-            Log.i(TAG, "onSuccessInternal: returned response");
         } catch (RemoteException e) {
             Log.w(TAG, "Error returning wallet cards", e);
         }
@@ -106,29 +101,53 @@
     }
 
     private boolean isValidResponse(@NonNull GetWalletCardsResponse response) {
-        return response != null
-                && response.getWalletCards() != null
-                && response.getSelectedIndex() >= 0
-                && (response.getWalletCards().isEmpty() // selectedIndex may be 0 when list is empty
-                || response.getSelectedIndex() < response.getWalletCards().size())
-                && response.getWalletCards().size() < mRequest.getMaxCards()
-                && areValidCards(response.getWalletCards());
-    }
-
-    private boolean areValidCards(List<WalletCard> walletCards) {
-        for (WalletCard walletCard : walletCards) {
-            if (walletCard == null
-                    || walletCard.getCardId() == null
-                    || walletCard.getCardImage() == null
-                    || TextUtils.isEmpty(walletCard.getContentDescription())
-                    || walletCard.getPendingIntent() == null) {
+        if (response == null) {
+            Log.w(TAG, "Invalid response: response is null");
+            return false;
+        }
+        if (response.getWalletCards() == null) {
+            Log.w(TAG, "Invalid response: walletCards is null");
+            return false;
+        }
+        if (response.getSelectedIndex() < 0) {
+            Log.w(TAG, "Invalid response: selectedIndex is negative");
+            return false;
+        }
+        if (!response.getWalletCards().isEmpty()
+                && response.getSelectedIndex() >= response.getWalletCards().size()) {
+            Log.w(TAG, "Invalid response: selectedIndex out of bounds");
+            return false;
+        }
+        if (response.getWalletCards().size() > mRequest.getMaxCards()) {
+            Log.w(TAG, "Invalid response: too many cards");
+            return false;
+        }
+        for (WalletCard walletCard : response.getWalletCards()) {
+            if (walletCard == null) {
+                Log.w(TAG, "Invalid response: card is null");
+                return false;
+            }
+            if (walletCard.getCardId() == null) {
+                Log.w(TAG, "Invalid response: cardId is null");
                 return false;
             }
             Icon cardImage = walletCard.getCardImage();
+            if (cardImage == null) {
+                Log.w(TAG, "Invalid response: cardImage is null");
+                return false;
+            }
             if (cardImage.getType() == Icon.TYPE_BITMAP
-                    && walletCard.getCardImage().getBitmap().getConfig()
-                    != Bitmap.Config.HARDWARE) {
-                Log.w(TAG, "WalletCard bitmaps should be hardware bitmaps");
+                    && cardImage.getBitmap().getConfig() != Bitmap.Config.HARDWARE) {
+                Log.w(TAG, "Invalid response: cardImage bitmaps must be hardware bitmaps");
+                return false;
+            }
+            if (TextUtils.isEmpty(walletCard.getContentDescription())) {
+                Log.w(TAG, "Invalid response: contentDescription is null");
+                return false;
+            }
+            if (walletCard.getPendingIntent() == null) {
+                Log.w(TAG, "Invalid response: pendingIntent is null");
+                return false;
             }
         }
         return true;
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
index be9ab11..4f5b139 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
@@ -16,19 +16,23 @@
 
 package android.service.quickaccesswallet;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.content.Context;
 import android.content.Intent;
 
+import java.io.Closeable;
+import java.util.concurrent.Executor;
+
 /**
  * Facilitates accessing cards from the {@link QuickAccessWalletService}.
  *
  * @hide
  */
 @TestApi
-public interface QuickAccessWalletClient {
+public interface QuickAccessWalletClient extends Closeable {
 
     /**
      * Create a client for accessing wallet cards from the {@link QuickAccessWalletService}. If the
@@ -92,6 +96,14 @@
             @NonNull OnWalletCardsRetrievedCallback callback);
 
     /**
+     * Get wallet cards from the {@link QuickAccessWalletService}.
+     */
+    void getWalletCards(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull GetWalletCardsRequest request,
+            @NonNull OnWalletCardsRetrievedCallback callback);
+
+    /**
      * Callback for getWalletCards
      */
     interface OnWalletCardsRetrievedCallback {
@@ -111,12 +123,19 @@
     void notifyWalletDismissed();
 
     /**
-     * Unregister event listener.
+     * Register an event listener.
      */
     void addWalletServiceEventListener(@NonNull WalletServiceEventListener listener);
 
     /**
-     * Unregister event listener
+     * Register an event listener.
+     */
+    void addWalletServiceEventListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull WalletServiceEventListener listener);
+
+    /**
+     * Unregister an event listener
      */
     void removeWalletServiceEventListener(@NonNull WalletServiceEventListener listener);
 
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
index 37a8703..e4dd082 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
@@ -18,6 +18,7 @@
 
 import static android.service.quickaccesswallet.QuickAccessWalletService.SERVICE_INTERFACE;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -36,16 +37,19 @@
 
 import com.android.internal.widget.LockPatternUtils;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.Queue;
 import java.util.UUID;
+import java.util.concurrent.Executor;
 
 /**
  * Implements {@link QuickAccessWalletClient}. The client connects, performs requests, waits for
- * responses, and disconnects automatically after a short period of time. The client may
+ * responses, and disconnects automatically one minute after the last call is performed.
+ *
  * @hide
  */
 public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, ServiceConnection {
@@ -78,15 +82,14 @@
 
     @Override
     public boolean isWalletServiceAvailable() {
-        boolean available = mServiceInfo != null;
-        Log.i(TAG, "isWalletServiceAvailable: " + available);
-        return available;
+        return mServiceInfo != null;
     }
 
     @Override
     public boolean isWalletFeatureAvailable() {
         int currentUser = ActivityManager.getCurrentUser();
-        return checkUserSetupComplete()
+        return currentUser == UserHandle.USER_SYSTEM
+                && checkUserSetupComplete()
                 && checkSecureSetting(Settings.Secure.GLOBAL_ACTIONS_PANEL_ENABLED)
                 && !new LockPatternUtils(mContext).isUserInLockdown(currentUser);
     }
@@ -101,23 +104,29 @@
     public void getWalletCards(
             @NonNull GetWalletCardsRequest request,
             @NonNull OnWalletCardsRetrievedCallback callback) {
+        getWalletCards(mContext.getMainExecutor(), request, callback);
+    }
 
-        Log.i(TAG, "getWalletCards");
-
+    @Override
+    public void getWalletCards(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull GetWalletCardsRequest request,
+            @NonNull OnWalletCardsRetrievedCallback callback) {
         if (!isWalletServiceAvailable()) {
-            callback.onWalletCardRetrievalError(new GetWalletCardsError(null, null));
+            executor.execute(
+                    () -> callback.onWalletCardRetrievalError(new GetWalletCardsError(null, null)));
             return;
         }
 
         BaseCallbacks serviceCallback = new BaseCallbacks() {
             @Override
             public void onGetWalletCardsSuccess(GetWalletCardsResponse response) {
-                mHandler.post(() -> callback.onWalletCardsRetrieved(response));
+                executor.execute(() -> callback.onWalletCardsRetrieved(response));
             }
 
             @Override
             public void onGetWalletCardsFailure(GetWalletCardsError error) {
-                mHandler.post(() -> callback.onWalletCardRetrievalError(error));
+                executor.execute(() -> callback.onWalletCardRetrievalError(error));
             }
         };
 
@@ -132,11 +141,11 @@
                 serviceCallback.onGetWalletCardsFailure(new GetWalletCardsError(null, null));
             }
         });
+
     }
 
     @Override
     public void selectWalletCard(@NonNull SelectWalletCardRequest request) {
-        Log.i(TAG, "selectWalletCard");
         if (!isWalletServiceAvailable()) {
             return;
         }
@@ -153,7 +162,6 @@
         if (!isWalletServiceAvailable()) {
             return;
         }
-        Log.i(TAG, "notifyWalletDismissed");
         executeApiCall(new ApiCaller("onWalletDismissed") {
             @Override
             public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
@@ -164,15 +172,20 @@
 
     @Override
     public void addWalletServiceEventListener(WalletServiceEventListener listener) {
+        addWalletServiceEventListener(mContext.getMainExecutor(), listener);
+    }
+
+    @Override
+    public void addWalletServiceEventListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull WalletServiceEventListener listener) {
         if (!isWalletServiceAvailable()) {
             return;
         }
-        Log.i(TAG, "registerWalletServiceEventListener");
         BaseCallbacks callback = new BaseCallbacks() {
             @Override
             public void onWalletServiceEvent(WalletServiceEvent event) {
-                Log.i(TAG, "onWalletServiceEvent");
-                mHandler.post(() -> listener.onWalletServiceEvent(event));
+                executor.execute(() -> listener.onWalletServiceEvent(event));
             }
         };
 
@@ -193,7 +206,6 @@
         if (!isWalletServiceAvailable()) {
             return;
         }
-        Log.i(TAG, "unregisterWalletServiceEventListener");
         executeApiCall(new ApiCaller("unregisterListener") {
             @Override
             public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
@@ -209,8 +221,12 @@
     }
 
     @Override
+    public void close() throws IOException {
+        disconnect();
+    }
+
+    @Override
     public void disconnect() {
-        Log.i(TAG, "disconnect");
         mHandler.post(() -> disconnectInternal(true));
     }
 
@@ -241,18 +257,15 @@
     }
 
     private void connect() {
-        Log.i(TAG, "connect");
         mHandler.post(this::connectInternal);
     }
 
     private void connectInternal() {
-        Log.i(TAG, "connectInternal");
         if (mServiceInfo == null) {
             Log.w(TAG, "Wallet service unavailable");
             return;
         }
         if (mIsConnected) {
-            Log.w(TAG, "already connected");
             return;
         }
         mIsConnected = true;
@@ -264,23 +277,14 @@
     }
 
     private void onConnectedInternal(IQuickAccessWalletService service) {
-        Log.i(TAG, "onConnectedInternal");
         if (!mIsConnected) {
             Log.w(TAG, "onConnectInternal but connection closed");
             mService = null;
             return;
         }
         mService = service;
-        Log.i(TAG, "onConnectedInternal success: request queue size " + mRequestQueue.size());
         for (ApiCaller apiCaller : new ArrayList<>(mRequestQueue)) {
-            try {
-                apiCaller.performApiCall(mService);
-            } catch (RemoteException e) {
-                Log.e(TAG, "onConnectedInternal error", e);
-                apiCaller.onApiError();
-                disconnect();
-                break;
-            }
+            performApiCallInternal(apiCaller, mService);
             mRequestQueue.remove(apiCaller);
         }
     }
@@ -290,7 +294,6 @@
      * posting a new delayed message.
      */
     private void resetServiceConnectionTimeout() {
-        Log.i(TAG, "resetServiceConnectionTimeout");
         mHandler.removeMessages(MSG_TIMEOUT_SERVICE);
         mHandler.postDelayed(
                 () -> disconnectInternal(true),
@@ -299,13 +302,11 @@
     }
 
     private void disconnectInternal(boolean clearEventListeners) {
-        Log.i(TAG, "disconnectInternal: " + clearEventListeners);
         if (!mIsConnected) {
             Log.w(TAG, "already disconnected");
             return;
         }
         if (clearEventListeners && !mEventListeners.isEmpty()) {
-            Log.i(TAG, "disconnectInternal: clear event listeners");
             for (WalletServiceEventListener listener : mEventListeners.keySet()) {
                 removeWalletServiceEventListener(listener);
             }
@@ -320,29 +321,33 @@
     }
 
     private void executeApiCall(ApiCaller apiCaller) {
-        Log.i(TAG, "execute: " + apiCaller.mDesc);
         mHandler.post(() -> executeInternal(apiCaller));
     }
 
-    private void executeInternal(ApiCaller apiCall) {
-        Log.i(TAG, "executeInternal: " + apiCall.mDesc);
+    private void executeInternal(ApiCaller apiCaller) {
         if (mIsConnected && mService != null) {
-            try {
-                apiCall.performApiCall(mService);
-                Log.i(TAG, "executeInternal success: " + apiCall.mDesc);
-                resetServiceConnectionTimeout();
-            } catch (RemoteException e) {
-                Log.w(TAG, "executeInternal error: " + apiCall.mDesc, e);
-                apiCall.onApiError();
-                disconnect();
-            }
+            performApiCallInternal(apiCaller, mService);
         } else {
-            Log.i(TAG, "executeInternal: queued" + apiCall.mDesc);
-            mRequestQueue.add(apiCall);
+            mRequestQueue.add(apiCaller);
             connect();
         }
     }
 
+    private void performApiCallInternal(ApiCaller apiCaller, IQuickAccessWalletService service) {
+        if (service == null) {
+            apiCaller.onApiError();
+            return;
+        }
+        try {
+            apiCaller.performApiCall(service);
+            resetServiceConnectionTimeout();
+        } catch (RemoteException e) {
+            Log.w(TAG, "executeInternal error: " + apiCaller.mDesc, e);
+            apiCaller.onApiError();
+            disconnect();
+        }
+    }
+
     private abstract static class ApiCaller {
         private final String mDesc;
 
@@ -350,7 +355,8 @@
             this.mDesc = desc;
         }
 
-        abstract void performApiCall(IQuickAccessWalletService service) throws RemoteException;
+        abstract void performApiCall(IQuickAccessWalletService service)
+                throws RemoteException;
 
         void onApiError() {
             Log.w(TAG, "api error: " + mDesc);
@@ -359,7 +365,6 @@
 
     @Override // ServiceConnection
     public void onServiceConnected(ComponentName name, IBinder binder) {
-        Log.i(TAG, "onServiceConnected: " + name);
         IQuickAccessWalletService service = IQuickAccessWalletService.Stub.asInterface(binder);
         mHandler.post(() -> onConnectedInternal(service));
     }
@@ -367,19 +372,16 @@
     @Override // ServiceConnection
     public void onServiceDisconnected(ComponentName name) {
         // Do not disconnect, as we may later be re-connected
-        Log.w(TAG, "onServiceDisconnected");
     }
 
     @Override // ServiceConnection
     public void onBindingDied(ComponentName name) {
         // This is a recoverable error but the client will need to reconnect.
-        Log.w(TAG, "onBindingDied");
         disconnect();
     }
 
     @Override // ServiceConnection
     public void onNullBinding(ComponentName name) {
-        Log.w(TAG, "onNullBinding");
         disconnect();
     }
 
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
index 23173a8..31e51bb 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -66,13 +66,11 @@
     static QuickAccessWalletServiceInfo tryCreate(@NonNull Context context) {
         ComponentName defaultPaymentApp = getDefaultPaymentApp(context);
         if (defaultPaymentApp == null) {
-            Log.d(TAG, "create: default payment app not set");
             return null;
         }
 
         ServiceInfo serviceInfo = getWalletServiceInfo(context, defaultPaymentApp.getPackageName());
         if (serviceInfo == null) {
-            Log.d(TAG, "create: unable to resolve service intent");
             return null;
         }
 
diff --git a/core/java/android/service/quickaccesswallet/WalletCard.java b/core/java/android/service/quickaccesswallet/WalletCard.java
index e6ae0ab..b09d2e9 100644
--- a/core/java/android/service/quickaccesswallet/WalletCard.java
+++ b/core/java/android/service/quickaccesswallet/WalletCard.java
@@ -180,7 +180,7 @@
          *                           GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
          *                           GetWalletCardsRequest#getCardHeightPx()}. If the card image
          *                           does not have these dimensions, it may appear distorted when it
-         *                           is scaled to fit these dimensions on screen. Bitmaps should be
+         *                           is scaled to fit these dimensions on screen. Bitmaps must be
          *                           of type {@link android.graphics.Bitmap.Config#HARDWARE} for
          *                           performance reasons.
          * @param contentDescription The content description of the card image. This field is
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 8e6f77b..4a0dd87 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1314,7 +1314,8 @@
             intent.migrateExtraStreamToClipData();
             intent.prepareToLeaveProcess(mContext);
             int res = mSystemService.startVoiceActivity(mToken, intent,
-                    intent.resolveType(mContext.getContentResolver()), mContext.getFeatureId());
+                    intent.resolveType(mContext.getContentResolver()),
+                    mContext.getAttributionTag());
             Instrumentation.checkStartActivityResult(res, intent);
         } catch (RemoteException e) {
         }
@@ -1342,7 +1343,8 @@
             intent.migrateExtraStreamToClipData();
             intent.prepareToLeaveProcess(mContext);
             int res = mSystemService.startAssistantActivity(mToken, intent,
-                    intent.resolveType(mContext.getContentResolver()), mContext.getFeatureId());
+                    intent.resolveType(mContext.getContentResolver()),
+                    mContext.getAttributionTag());
             Instrumentation.checkStartActivityResult(res, intent);
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index e93ba16..92f3538 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -342,7 +342,7 @@
         }
         try {
             mService.startListening(recognizerIntent, mListener, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
             if (DBG) Log.d(TAG, "service start listening command succeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "startListening() failed", e);
@@ -357,7 +357,7 @@
         }
         try {
             mService.stopListening(mListener, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
             if (DBG) Log.d(TAG, "service stop listening command succeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "stopListening() failed", e);
@@ -371,7 +371,7 @@
             return;
         }
         try {
-            mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
+            mService.cancel(mListener, mContext.getOpPackageName(), mContext.getAttributionTag());
             if (DBG) Log.d(TAG, "service cancel command succeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "cancel() failed", e);
@@ -400,7 +400,8 @@
     public void destroy() {
         if (mService != null) {
             try {
-                mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
+                mService.cancel(mListener, mContext.getOpPackageName(),
+                        mContext.getAttributionTag());
             } catch (final RemoteException e) {
                 // Not important
             }
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 7238b12..ab9df56 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -116,7 +116,7 @@
         mSubscriptionChangedListenerMap.put(listener, callback);
         try {
             sRegistry.addOnSubscriptionsChangedListener(mContext.getOpPackageName(),
-                    mContext.getFeatureId(), callback);
+                    mContext.getAttributionTag(), callback);
         } catch (RemoteException ex) {
             // system server crash
         }
@@ -175,7 +175,7 @@
         mOpportunisticSubscriptionChangedListenerMap.put(listener, callback);
         try {
             sRegistry.addOnOpportunisticSubscriptionsChangedListener(mContext.getOpPackageName(),
-                    mContext.getFeatureId(), callback);
+                    mContext.getAttributionTag(), callback);
         } catch (RemoteException ex) {
             // system server crash
         }
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index abd04cc..79eb9f6 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -16,6 +16,8 @@
 
 package android.util.apk;
 
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512;
 import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
 import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm;
@@ -211,6 +213,12 @@
                     verityDigest, apk.length(), signatureInfo);
         }
 
+        if (contentDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA512)) {
+            result.digest = contentDigests.get(CONTENT_DIGEST_CHUNKED_SHA512);
+        } else if (contentDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA256)) {
+            result.digest = contentDigests.get(CONTENT_DIGEST_CHUNKED_SHA256);
+        }
+
         return result;
     }
 
@@ -568,6 +576,7 @@
         public final VerifiedProofOfRotation por;
 
         public byte[] verityRootHash;
+        public byte[] digest;
 
         public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por) {
             this.certs = certs;
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
index b6b8089..8c240d9 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
@@ -16,13 +16,32 @@
 
 package android.util.apk;
 
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
+
 import android.os.incremental.IncrementalManager;
+import android.os.incremental.V4Signature;
+import android.util.Pair;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
 import java.security.cert.Certificate;
-
-import sun.security.pkcs.PKCS7;
-import sun.security.pkcs.ParsingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
 
 /**
  * APK Signature Scheme v4 verifier.
@@ -30,24 +49,118 @@
  * @hide for internal use only.
  */
 public class ApkSignatureSchemeV4Verifier {
+    /**
+     * Extracts and verifies APK Signature Scheme v4 signatures of the provided APK and returns the
+     * certificates associated with each signer.
+     */
+    public static VerifiedSigner extractCertificates(String apkFile)
+            throws SignatureNotFoundException, SecurityException {
+        final File apk = new File(apkFile);
+        final byte[] signatureBytes = IncrementalManager.unsafeGetFileSignature(
+                apk.getAbsolutePath());
+        if (signatureBytes == null || signatureBytes.length == 0) {
+            throw new SignatureNotFoundException("Failed to obtain signature bytes from IncFS.");
+        }
+
+        final V4Signature signature;
+        final V4Signature.HashingInfo hashingInfo;
+        final V4Signature.SigningInfo signingInfo;
+        try {
+            signature = V4Signature.readFrom(signatureBytes);
+
+            if (!signature.isVersionSupported()) {
+                throw new SecurityException(
+                        "v4 signature version " + signature.version + " is not supported");
+            }
+
+            hashingInfo = V4Signature.HashingInfo.fromByteArray(signature.hashingInfo);
+            signingInfo = V4Signature.SigningInfo.fromByteArray(signature.signingInfo);
+        } catch (IOException e) {
+            throw new SignatureNotFoundException("Failed to read V4 signature.", e);
+        }
+
+        final byte[] signedData = V4Signature.getSigningData(apk.length(), hashingInfo,
+                signingInfo);
+
+        return verifySigner(signingInfo, signedData);
+    }
+
+    private static VerifiedSigner verifySigner(V4Signature.SigningInfo signingInfo,
+            final byte[] signedData) throws SecurityException {
+        if (!isSupportedSignatureAlgorithm(signingInfo.signatureAlgorithmId)) {
+            throw new SecurityException("No supported signatures found");
+        }
+
+        final int signatureAlgorithmId = signingInfo.signatureAlgorithmId;
+        final byte[] signatureBytes = signingInfo.signature;
+        final byte[] publicKeyBytes = signingInfo.publicKey;
+        final byte[] encodedCert = signingInfo.certificate;
+
+        String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(signatureAlgorithmId);
+        Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams =
+                getSignatureAlgorithmJcaSignatureAlgorithm(signatureAlgorithmId);
+        String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
+        AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
+        boolean sigVerified;
+        try {
+            PublicKey publicKey =
+                    KeyFactory.getInstance(keyAlgorithm)
+                            .generatePublic(new X509EncodedKeySpec(publicKeyBytes));
+            Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
+            sig.initVerify(publicKey);
+            if (jcaSignatureAlgorithmParams != null) {
+                sig.setParameter(jcaSignatureAlgorithmParams);
+            }
+            sig.update(signedData);
+            sigVerified = sig.verify(signatureBytes);
+        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException
+                | InvalidAlgorithmParameterException | SignatureException e) {
+            throw new SecurityException(
+                    "Failed to verify " + jcaSignatureAlgorithm + " signature", e);
+        }
+        if (!sigVerified) {
+            throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
+        }
+
+        // Signature over signedData has verified.
+        CertificateFactory certFactory;
+        try {
+            certFactory = CertificateFactory.getInstance("X.509");
+        } catch (CertificateException e) {
+            throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
+        }
+
+        X509Certificate certificate;
+        try {
+            certificate = (X509Certificate)
+                    certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
+        } catch (CertificateException e) {
+            throw new SecurityException("Failed to decode certificate", e);
+        }
+        certificate = new VerbatimX509Certificate(certificate, encodedCert);
+
+        byte[] certificatePublicKeyBytes = certificate.getPublicKey().getEncoded();
+        if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
+            throw new SecurityException(
+                    "Public key mismatch between certificate and signature record");
+        }
+
+        return new VerifiedSigner(new Certificate[]{certificate}, signingInfo.v3Digest);
+    }
 
     /**
-     * Extracts APK Signature Scheme v4 signatures of the provided APK and returns the certificates
-     * associated with each signer.
+     * Verified APK Signature Scheme v4 signer, including V3 digest.
+     *
+     * @hide for internal use only.
      */
-    public static Certificate[] extractCertificates(String apkFile)
-            throws SignatureNotFoundException, SecurityException {
-        final byte[] rawSignature = IncrementalManager.unsafeGetFileSignature(
-                new File(apkFile).getAbsolutePath());
-        if (rawSignature == null || rawSignature.length == 0) {
-            throw new SignatureNotFoundException("Failed to obtain raw signature from IncFS.");
+    public static class VerifiedSigner {
+        public final Certificate[] certs;
+        public byte[] v3Digest;
+
+        public VerifiedSigner(Certificate[] certs, byte[] v3Digest) {
+            this.certs = certs;
+            this.v3Digest = v3Digest;
         }
 
-        try {
-            PKCS7 pkcs7 = new PKCS7(rawSignature);
-            return pkcs7.getCertificates();
-        } catch (ParsingException e) {
-            throw new SecurityException("Failed to parse signature and extract certificates", e);
-        }
     }
 }
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index f325c21..c1cee48 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -168,7 +168,7 @@
     /**
      * Verifies the provided APK using V4 schema.
      *
-     * @param verifyFull whether to verify all contents of this APK or just collect certificates.
+     * @param verifyFull whether to verify (V4 vs V3) or just collect certificates.
      * @return the certificates associated with each signer.
      * @throws SignatureNotFoundException if there are no V4 signatures in the APK
      * @throws PackageParserException     if there was a problem collecting certificates
@@ -178,30 +178,34 @@
             throws SignatureNotFoundException, PackageParserException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4");
         try {
-            Certificate[] certs = ApkSignatureSchemeV4Verifier.extractCertificates(apkPath);
-            Certificate[][] signerCerts = new Certificate[][]{certs};
+            ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner =
+                    ApkSignatureSchemeV4Verifier.extractCertificates(apkPath);
+            Certificate[][] signerCerts = new Certificate[][]{vSigner.certs};
             Signature[] signerSigs = convertToSignatures(signerCerts);
 
             if (verifyFull) {
-                // v4 is an add-on and requires v2/v3 signature to validate against its certificates
-                final PackageParser.SigningDetails nonstreaming = verifyV3AndBelowSignatures(
-                        apkPath, minSignatureSchemeVersion, false);
-                if (nonstreaming.signatureSchemeVersion <= SignatureSchemeVersion.JAR) {
+                // v4 is an add-on and requires v3 signature to validate against its certificates
+                ApkSignatureSchemeV3Verifier.VerifiedSigner nonstreaming =
+                        ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
+                Certificate[][] nonstreamingCerts = new Certificate[][]{nonstreaming.certs};
+                Signature[] nonstreamingSigs = convertToSignatures(nonstreamingCerts);
+
+                if (nonstreamingSigs.length != signerSigs.length) {
                     throw new SecurityException(
-                            "V4 signing block can only be verified along with V2 and above.");
-                }
-                if (nonstreaming.signatures.length == 0
-                        || nonstreaming.signatures.length != signerSigs.length) {
-                    throw new SecurityException("Invalid number of signatures in "
-                            + nonstreaming.signatureSchemeVersion);
+                            "Invalid number of certificates: " + nonstreaming.certs.length);
                 }
 
                 for (int i = 0, size = signerSigs.length; i < size; ++i) {
-                    if (!nonstreaming.signatures[i].equals(signerSigs[i])) {
-                        throw new SecurityException("V4 signature certificate does not match "
-                                + nonstreaming.signatureSchemeVersion);
+                    if (!nonstreamingSigs[i].equals(signerSigs[i])) {
+                        throw new SecurityException("V4 signature certificate does not match V3");
                     }
                 }
+
+                // TODO(b/151240006): add support for v2 digest and make it mandatory.
+                if (!ArrayUtils.isEmpty(vSigner.v3Digest) && !ArrayUtils.equals(vSigner.v3Digest,
+                        nonstreaming.digest, vSigner.v3Digest.length)) {
+                    throw new SecurityException("V3 digest in V4 signature does not match V3");
+                }
             }
 
             return new PackageParser.SigningDetails(signerSigs,
diff --git a/core/java/android/util/apk/SourceStampVerifier.java b/core/java/android/util/apk/SourceStampVerifier.java
index 759c864..a7ae32d 100644
--- a/core/java/android/util/apk/SourceStampVerifier.java
+++ b/core/java/android/util/apk/SourceStampVerifier.java
@@ -24,6 +24,7 @@
 import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
 
 import android.util.Pair;
+import android.util.Slog;
 import android.util.jar.StrictJarFile;
 
 import libcore.io.IoUtils;
@@ -43,6 +44,7 @@
 import java.security.PublicKey;
 import java.security.Signature;
 import java.security.SignatureException;
+import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
@@ -68,6 +70,8 @@
  */
 public abstract class SourceStampVerifier {
 
+    private static final String TAG = "SourceStampVerifier";
+
     private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
     private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0;
     private static final int SOURCE_STAMP_BLOCK_ID = 0x2b09189e;
@@ -78,29 +82,59 @@
     /** Hidden constructor to prevent instantiation. */
     private SourceStampVerifier() {}
 
+    /** Verifies SourceStamp present in a list of APKs. */
+    public static SourceStampVerificationResult verify(List<String> apkFiles) {
+        Certificate stampCertificate = null;
+        for (String apkFile : apkFiles) {
+            SourceStampVerificationResult sourceStampVerificationResult = verify(apkFile);
+            if (!sourceStampVerificationResult.isPresent()
+                    || !sourceStampVerificationResult.isVerified()) {
+                return sourceStampVerificationResult;
+            }
+            if (stampCertificate != null
+                    && !stampCertificate.equals(sourceStampVerificationResult.getCertificate())) {
+                return SourceStampVerificationResult.notVerified();
+            }
+            stampCertificate = sourceStampVerificationResult.getCertificate();
+        }
+        return SourceStampVerificationResult.verified(stampCertificate);
+    }
+
     /** Verifies SourceStamp present in the provided APK. */
     public static SourceStampVerificationResult verify(String apkFile) {
+        StrictJarFile apkJar = null;
         try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
-            return verify(apk);
-        } catch (Exception e) {
-            // Any exception in the SourceStamp verification returns a non-verified SourceStamp
-            // outcome without affecting the outcome of any of the other signature schemes.
-            return SourceStampVerificationResult.notVerified();
+            apkJar =
+                    new StrictJarFile(
+                            apkFile,
+                            /* verify= */ false,
+                            /* signatureSchemeRollbackProtectionsEnforced= */ false);
+            byte[] sourceStampCertificateDigest = getSourceStampCertificateDigest(apkJar);
+            if (sourceStampCertificateDigest == null) {
+                // SourceStamp certificate hash file not found, which means that there is not
+                // SourceStamp present.
+                return SourceStampVerificationResult.notPresent();
+            }
+            return verify(apk, sourceStampCertificateDigest);
+        } catch (IOException e) {
+            // Any exception in reading the APK returns a non-present SourceStamp outcome
+            // without affecting the outcome of any of the other signature schemes.
+            return SourceStampVerificationResult.notPresent();
+        } finally {
+            closeApkJar(apkJar);
         }
     }
 
-    private static SourceStampVerificationResult verify(RandomAccessFile apk)
-            throws IOException, SignatureNotFoundException {
-        byte[] sourceStampCertificateDigest = getSourceStampCertificateDigest(apk);
-        if (sourceStampCertificateDigest == null) {
-            // SourceStamp certificate hash file not found, which means that there is not
-            // SourceStamp present.
-            return SourceStampVerificationResult.notPresent();
+    private static SourceStampVerificationResult verify(
+            RandomAccessFile apk, byte[] sourceStampCertificateDigest) {
+        try {
+            SignatureInfo signatureInfo =
+                    ApkSigningBlockUtils.findSignature(apk, SOURCE_STAMP_BLOCK_ID);
+            Map<Integer, byte[]> apkContentDigests = getApkContentDigests(apk);
+            return verify(signatureInfo, apkContentDigests, sourceStampCertificateDigest);
+        } catch (IOException | SignatureNotFoundException e) {
+            return SourceStampVerificationResult.notVerified();
         }
-        SignatureInfo signatureInfo =
-                ApkSigningBlockUtils.findSignature(apk, SOURCE_STAMP_BLOCK_ID);
-        Map<Integer, byte[]> apkContentDigests = getApkContentDigests(apk);
-        return verify(signatureInfo, apkContentDigests, sourceStampCertificateDigest);
     }
 
     private static SourceStampVerificationResult verify(
@@ -255,22 +289,17 @@
         return apkContentDigests;
     }
 
-    private static byte[] getSourceStampCertificateDigest(RandomAccessFile apk) throws IOException {
-        StrictJarFile apkJar =
-                new StrictJarFile(
-                        apk.getFD(),
-                        /* verify= */ false,
-                        /* signatureSchemeRollbackProtectionsEnforced= */ false);
-        ZipEntry zipEntry = apkJar.findEntry(SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME);
-        if (zipEntry == null) {
-            // SourceStamp certificate hash file not found, which means that there is not
-            // SourceStamp present.
-            return null;
-        }
+    private static byte[] getSourceStampCertificateDigest(StrictJarFile apkJar) throws IOException {
         InputStream inputStream = null;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         try {
+            ZipEntry zipEntry = apkJar.findEntry(SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME);
+            if (zipEntry == null) {
+                // SourceStamp certificate hash file not found, which means that there is not
+                // SourceStamp present.
+                return null;
+            }
             inputStream = apkJar.getInputStream(zipEntry);
+            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 
             // Trying to read the certificate digest, which should be less than 1024 bytes.
             byte[] buffer = new byte[1024];
@@ -299,4 +328,15 @@
         }
         return result.array();
     }
+
+    private static void closeApkJar(StrictJarFile apkJar) {
+        try {
+            if (apkJar == null) {
+                return;
+            }
+            apkJar.close();
+        } catch (IOException e) {
+            Slog.e(TAG, "Could not close APK jar", e);
+        }
+    }
 }
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 74fac2b..6784cf7 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -165,10 +165,16 @@
         if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) {
             return;
         }
-        if (mServedView == view || !view.hasImeFocus() || !view.hasWindowFocus()) {
+        if (!view.hasImeFocus() || !view.hasWindowFocus()) {
             return;
         }
-        mNextServedView = hasFocus ? view : null;
+        if (DEBUG) Log.d(TAG, "onViewFocusChanged, view=" + view + ", mServedView=" + mServedView);
+
+        if (hasFocus) {
+            mNextServedView = view;
+        } else if (view == mServedView) {
+            mNextServedView = null;
+        }
         mViewRootImpl.dispatchCheckFocus();
     }
 
diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java
index 5d5edec..4227f78 100644
--- a/core/java/android/view/InsetsAnimationControlCallbacks.java
+++ b/core/java/android/view/InsetsAnimationControlCallbacks.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.view.InsetsController.LayoutInsetsDuringAnimation;
 import android.view.WindowInsetsAnimation.Bounds;
 
 /**
@@ -37,7 +36,7 @@
     void startAnimation(InsetsAnimationControlImpl controller,
             WindowInsetsAnimationControlListener listener, int types,
             WindowInsetsAnimation animation,
-            Bounds bounds, @LayoutInsetsDuringAnimation int layoutDuringAnimation);
+            Bounds bounds);
 
     /**
      * Schedule the apply by posting the animation callback.
@@ -46,10 +45,10 @@
 
     /**
      * Finish the final steps after the animation.
-     * @param controller The controller used to control the animation.
+     * @param runner The runner used to run the animation.
      * @param shown {@code true} if the insets are shown.
      */
-    void notifyFinished(InsetsAnimationControlImpl controller, boolean shown);
+    void notifyFinished(InsetsAnimationControlRunner runner, boolean shown);
 
     /**
      * Apply the new params to the surface.
@@ -57,4 +56,10 @@
      *               apply.
      */
     void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params);
+
+    /**
+     * Post a message to release the Surface, guaranteed to happen after all
+     * previous calls to applySurfaceParams.
+     */
+    void releaseSurfaceControlFromRt(SurfaceControl sc);
 }
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index ae509f3..baee412 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -31,9 +31,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.SparseSetArray;
-import android.view.InsetsController.LayoutInsetsDuringAnimation;
 import android.view.InsetsState.InternalInsetsSide;
-import android.view.InsetsState.InternalInsetsType;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsAnimation.Bounds;
@@ -49,7 +47,8 @@
  * @hide
  */
 @VisibleForTesting
-public class InsetsAnimationControlImpl implements WindowInsetsAnimationController  {
+public class InsetsAnimationControlImpl implements WindowInsetsAnimationController,
+        InsetsAnimationControlRunner {
 
     private final Rect mTmpFrame = new Rect();
 
@@ -84,8 +83,7 @@
             InsetsState state, WindowInsetsAnimationControlListener listener,
             @InsetsType int types,
             InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
-            boolean fade, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
-            @AnimationType int animationType) {
+            boolean fade, @AnimationType int animationType) {
         mControls = controls;
         mListener = listener;
         mTypes = types;
@@ -105,7 +103,7 @@
         mAnimation.setAlpha(getCurrentAlpha());
         mAnimationType = animationType;
         mController.startAnimation(this, listener, types, mAnimation,
-                new Bounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation);
+                new Bounds(mHiddenInsets, mShownInsets));
     }
 
     @Override
@@ -133,11 +131,8 @@
         return mTypes;
     }
 
-    boolean controlsInternalType(@InternalInsetsType int type) {
-        return InsetsState.toInternalType(mTypes).contains(type);
-    }
-
-    @AnimationType int getAnimationType() {
+    @Override
+    public @AnimationType int getAnimationType() {
         return mAnimationType;
     }
 
@@ -185,10 +180,19 @@
         mAnimation.setAlpha(mPendingAlpha);
         if (mFinished) {
             mController.notifyFinished(this, mShownOnFinish);
+            releaseLeashes();
         }
         return mFinished;
     }
 
+    private void releaseLeashes() {
+        for (int i = mControls.size() - 1; i >= 0; i--) {
+            final InsetsSourceControl c = mControls.valueAt(i);
+            if (c == null) continue;
+            c.release(mController::releaseSurfaceControlFromRt);
+        }
+    }
+
     @Override
     public void finish(boolean shown) {
         if (mCancelled || mFinished) {
@@ -196,6 +200,7 @@
         }
         setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
         mFinished = true;
+
         mShownOnFinish = shown;
     }
 
@@ -205,19 +210,23 @@
         return mAnimation.getFraction();
     }
 
-    public void onCancelled() {
+    @Override
+    public void cancel() {
         if (mFinished) {
             return;
         }
         mCancelled = true;
         mListener.onCancelled();
+
+        releaseLeashes();
     }
 
     public boolean isCancelled() {
         return mCancelled;
     }
 
-    WindowInsetsAnimation getAnimation() {
+    @Override
+    public WindowInsetsAnimation getAnimation() {
         return mAnimation;
     }
 
@@ -225,6 +234,10 @@
         return mListener;
     }
 
+    SparseArray<InsetsSourceControl> getControls() {
+        return mControls;
+    }
+
     private Insets calculateInsets(InsetsState state, Rect frame,
             SparseArray<InsetsSourceControl> controls, boolean shown,
             @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java
new file mode 100644
index 0000000..0711c3e
--- /dev/null
+++ b/core/java/android/view/InsetsAnimationControlRunner.java
@@ -0,0 +1,56 @@
+/*
+ * 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.view;
+
+import android.view.InsetsController.AnimationType;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.WindowInsets.Type.InsetsType;
+
+/**
+ * Interface representing a runner for an insets animation.
+ *
+ * @hide
+ */
+public interface InsetsAnimationControlRunner {
+
+    /**
+     * @return The {@link InsetsType} the animation of this runner is controlling.
+     */
+    @InsetsType int getTypes();
+
+    /**
+     * Cancels the animation.
+     */
+    void cancel();
+
+    /**
+     * @return The animation this runner is running.
+     */
+    WindowInsetsAnimation getAnimation();
+
+    /**
+     * @return Whether {@link #getTypes()} maps to a specific {@link InternalInsetsType}.
+     */
+    default boolean controlsInternalType(@InternalInsetsType int type) {
+        return InsetsState.toInternalType(getTypes()).contains(type);
+    }
+
+    /**
+     * @return The animation type this runner is running.
+     */
+    @AnimationType int getAnimationType();
+}
diff --git a/core/java/android/view/InsetsAnimationThread.java b/core/java/android/view/InsetsAnimationThread.java
new file mode 100644
index 0000000..cdf9733
--- /dev/null
+++ b/core/java/android/view/InsetsAnimationThread.java
@@ -0,0 +1,70 @@
+/*
+ * 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.view;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Trace;
+
+/**
+ * Thread to be used for inset animations to be running off the main thread.
+ * @hide
+ */
+public class InsetsAnimationThread extends HandlerThread {
+
+    private static InsetsAnimationThread sInstance;
+    private static Handler sHandler;
+
+    private InsetsAnimationThread() {
+        // TODO: Should this use higher priority?
+        super("InsetsAnimations");
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new InsetsAnimationThread();
+            sInstance.start();
+            sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_VIEW);
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static void release() {
+        synchronized (InsetsAnimationThread.class) {
+            if (sInstance == null) {
+                return;
+            }
+            sInstance.getLooper().quitSafely();
+            sInstance = null;
+            sHandler = null;
+        }
+    }
+
+    public static InsetsAnimationThread get() {
+        synchronized (InsetsAnimationThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (InsetsAnimationThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
new file mode 100644
index 0000000..13b4cd8
--- /dev/null
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -0,0 +1,136 @@
+/*
+ * 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.view;
+
+import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
+
+import android.annotation.UiThread;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.SparseArray;
+import android.view.InsetsController.AnimationType;
+import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowInsetsAnimation.Bounds;
+import android.view.animation.Interpolator;
+
+/**
+ * Insets animation runner that uses {@link InsetsAnimationThread} to run the animation off from the
+ * main thread.
+ *
+ * @hide
+ */
+public class InsetsAnimationThreadControlRunner implements InsetsAnimationControlRunner {
+
+    private final InsetsAnimationControlImpl mControl;
+    private final InsetsAnimationControlCallbacks mOuterCallbacks;
+    private final Handler mMainThreadHandler;
+    private final InsetsState mState = new InsetsState();
+    private final InsetsAnimationControlCallbacks mCallbacks =
+            new InsetsAnimationControlCallbacks() {
+
+        private final float[] mTmpFloat9 = new float[9];
+
+        @Override
+        @UiThread
+        public void startAnimation(InsetsAnimationControlImpl controller,
+                WindowInsetsAnimationControlListener listener, int types,
+                WindowInsetsAnimation animation, Bounds bounds) {
+            // Animation will be started in constructor already.
+        }
+
+        @Override
+        public void scheduleApplyChangeInsets() {
+            mControl.applyChangeInsets(mState);
+        }
+
+        @Override
+        public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
+            releaseControls(mControl.getControls());
+            mMainThreadHandler.post(() ->
+                    mOuterCallbacks.notifyFinished(InsetsAnimationThreadControlRunner.this, shown));
+        }
+
+        @Override
+        public void applySurfaceParams(SurfaceParams... params) {
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            for (int i = params.length - 1; i >= 0; i--) {
+                SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
+                applyParams(t, surfaceParams, mTmpFloat9);
+            }
+            t.apply();
+            t.close();
+        }
+
+        @Override
+        public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+            // Since we don't push the SurfaceParams to the RT we can release directly
+            sc.release();
+        }
+    };
+
+    @UiThread
+    public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, Rect frame,
+            InsetsState state, WindowInsetsAnimationControlListener listener,
+            @InsetsType int types,
+            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
+            boolean fade, @AnimationType int animationType, Handler mainThreadHandler) {
+        mMainThreadHandler = mainThreadHandler;
+        mOuterCallbacks = controller;
+        mControl = new InsetsAnimationControlImpl(copyControls(controls), frame, state, listener,
+                types, mCallbacks, durationMs, interpolator, fade, animationType);
+        InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
+    }
+
+    private void releaseControls(SparseArray<InsetsSourceControl> controls) {
+        for (int i = controls.size() - 1; i >= 0; i--) {
+            controls.valueAt(i).release(SurfaceControl::release);
+        }
+    }
+
+    private SparseArray<InsetsSourceControl> copyControls(
+            SparseArray<InsetsSourceControl> controls) {
+        SparseArray<InsetsSourceControl> copy = new SparseArray<>(controls.size());
+        for (int i = 0; i < controls.size(); i++) {
+            copy.append(controls.keyAt(i), new InsetsSourceControl(controls.valueAt(i)));
+        }
+        return copy;
+    }
+
+    @Override
+    @UiThread
+    public int getTypes() {
+        return mControl.getTypes();
+    }
+
+    @Override
+    @UiThread
+    public void cancel() {
+        InsetsAnimationThread.getHandler().post(mControl::cancel);
+    }
+
+    @Override
+    @UiThread
+    public WindowInsetsAnimation getAnimation() {
+        return mControl.getAnimation();
+    }
+
+    @Override
+    public int getAnimationType() {
+        return mControl.getAnimationType();
+    }
+}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 607886f..123b9db 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
 
+import android.animation.AnimationHandler;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -52,7 +53,7 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -167,10 +168,22 @@
 
         private WindowInsetsAnimationController mController;
         private ObjectAnimator mAnimator;
-        protected boolean mShow;
+        private final boolean mShow;
+        private final boolean mUseSfVsync;
 
-        public InternalAnimationControlListener(boolean show) {
+        private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+                new ThreadLocal<AnimationHandler>() {
+            @Override
+            protected AnimationHandler initialValue() {
+                AnimationHandler handler = new AnimationHandler();
+                handler.setProvider(new SfVsyncFrameCallbackProvider());
+                return handler;
+            }
+        };
+
+        public InternalAnimationControlListener(boolean show, boolean useSfVsync) {
             mShow = show;
+            mUseSfVsync = useSfVsync;
         }
 
         @Override
@@ -193,6 +206,9 @@
                     onAnimationFinish();
                 }
             });
+            if (mUseSfVsync) {
+                mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
+            }
             mAnimator.start();
         }
 
@@ -228,12 +244,12 @@
      */
     private static class RunningAnimation {
 
-        RunningAnimation(InsetsAnimationControlImpl control, int type) {
-            this.control = control;
+        RunningAnimation(InsetsAnimationControlRunner runner, int type) {
+            this.runner = runner;
             this.type = type;
         }
 
-        final InsetsAnimationControlImpl control;
+        final InsetsAnimationControlRunner runner;
         final @AnimationType int type;
 
         /**
@@ -252,7 +268,7 @@
         PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
                 long durationMs, Interpolator interpolator, @AnimationType int animationType,
                 @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
-                CancellationSignal cancellationSignal) {
+                CancellationSignal cancellationSignal, boolean useInsetsAnimationThread) {
             this.types = types;
             this.listener = listener;
             this.durationMs = durationMs;
@@ -260,6 +276,7 @@
             this.animationType = animationType;
             this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
             this.cancellationSignal = cancellationSignal;
+            this.useInsetsAnimationThread = useInsetsAnimationThread;
         }
 
         final @InsetsType int types;
@@ -269,6 +286,7 @@
         final @AnimationType int animationType;
         final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
         final CancellationSignal cancellationSignal;
+        final boolean useInsetsAnimationThread;
     }
 
     private final String TAG = "InsetsControllerImpl";
@@ -347,15 +365,20 @@
             InsetsState state = new InsetsState(mState, true /* copySources */);
             for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                 RunningAnimation runningAnimation = mRunningAnimations.get(i);
-                InsetsAnimationControlImpl control = runningAnimation.control;
+                InsetsAnimationControlRunner runner = runningAnimation.runner;
+                if (runner instanceof InsetsAnimationControlImpl) {
+                    InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
 
-                // Keep track of running animation to be dispatched. Aggregate it here such that if
-                // it gets finished within applyChangeInsets we still dispatch it to onProgress.
-                if (runningAnimation.startDispatched) {
-                    mTmpRunningAnims.add(control.getAnimation());
-                }
-                if (control.applyChangeInsets(state)) {
-                    mTmpFinishedControls.add(control);
+                    // Keep track of running animation to be dispatched. Aggregate it here such that
+                    // if it gets finished within applyChangeInsets we still dispatch it to
+                    // onProgress.
+                    if (runningAnimation.startDispatched) {
+                        mTmpRunningAnims.add(control.getAnimation());
+                    }
+
+                    if (control.applyChangeInsets(state)) {
+                        mTmpFinishedControls.add(control);
+                    }
                 }
             }
 
@@ -494,13 +517,13 @@
             PendingControlRequest pendingRequest = mPendingImeControlRequest;
             mPendingImeControlRequest = null;
             mHandler.removeCallbacks(mPendingControlTimeout);
-            CancellationSignal cancellationSignal = controlAnimationUnchecked(
-                    pendingRequest.types,
+            controlAnimationUnchecked(
+                    pendingRequest.types, pendingRequest.cancellationSignal,
                     pendingRequest.listener, mFrame,
                     true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
                     false /* fade */, pendingRequest.animationType,
-                    pendingRequest.layoutInsetsDuringAnimation);
-            pendingRequest.cancellationSignal.setOnCancelListener(cancellationSignal::cancel);
+                    pendingRequest.layoutInsetsDuringAnimation,
+                    pendingRequest.useInsetsAnimationThread);
             return;
         }
 
@@ -546,24 +569,27 @@
     }
 
     @Override
-    public CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMs,
+    public void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
             @Nullable Interpolator interpolator,
+            @Nullable CancellationSignal cancellationSignal,
             @NonNull WindowInsetsAnimationControlListener listener) {
-        return controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs,
-                interpolator, ANIMATION_TYPE_USER);
+        controlWindowInsetsAnimation(types, cancellationSignal, listener,
+                false /* fromIme */, durationMillis, interpolator, ANIMATION_TYPE_USER);
     }
 
-    private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types,
-            WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs,
-            @Nullable Interpolator interpolator, @AnimationType int animationType) {
+    private void controlWindowInsetsAnimation(@InsetsType int types,
+            @Nullable CancellationSignal cancellationSignal,
+            WindowInsetsAnimationControlListener listener,
+            boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
+            @AnimationType int animationType) {
         if (!checkDisplayFramesForControlling()) {
             listener.onCancelled();
-            CancellationSignal cancellationSignal = new CancellationSignal();
-            cancellationSignal.cancel();
-            return cancellationSignal;
+            return;
         }
-        return controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
-                false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
+        controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
+                interpolator, false /* fade */, animationType,
+                getLayoutInsetsDuringAnimationMode(types),
+                false /* useInsetsAnimationThread */);
     }
 
     private boolean checkDisplayFramesForControlling() {
@@ -573,17 +599,17 @@
         return mState.getDisplayFrame().equals(mFrame);
     }
 
-    private CancellationSignal controlAnimationUnchecked(@InsetsType int types,
+    private void controlAnimationUnchecked(@InsetsType int types,
+            @Nullable CancellationSignal cancellationSignal,
             WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
             long durationMs, Interpolator interpolator, boolean fade,
             @AnimationType int animationType,
-            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
-        CancellationSignal cancellationSignal = new CancellationSignal();
+            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+            boolean useInsetsAnimationThread) {
         if (types == 0) {
             // nothing to animate.
             listener.onCancelled();
-            cancellationSignal.cancel();
-            return cancellationSignal;
+            return;
         }
         cancelExistingControllers(types);
         mLastStartedAnimTypes |= types;
@@ -600,29 +626,42 @@
             abortPendingImeControlRequest();
             final PendingControlRequest request = new PendingControlRequest(types,
                     listener, durationMs,
-                    interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal);
+                    interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal,
+                    useInsetsAnimationThread);
             mPendingImeControlRequest = request;
             mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
-            cancellationSignal.setOnCancelListener(() -> {
-                if (mPendingImeControlRequest == request) {
-                    abortPendingImeControlRequest();
-                }
-            });
-            return cancellationSignal;
+            if (cancellationSignal != null) {
+                cancellationSignal.setOnCancelListener(() -> {
+                    if (mPendingImeControlRequest == request) {
+                        abortPendingImeControlRequest();
+                    }
+                });
+            }
+            return;
         }
 
         if (typesReady == 0) {
             listener.onCancelled();
-            cancellationSignal.cancel();
-            return cancellationSignal;
+            return;
         }
 
-        final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
-                frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
-                layoutInsetsDuringAnimation, animationType);
-        mRunningAnimations.add(new RunningAnimation(controller, animationType));
-        cancellationSignal.setOnCancelListener(controller::onCancelled);
-        return cancellationSignal;
+
+        final InsetsAnimationControlRunner runner = useInsetsAnimationThread
+                ? new InsetsAnimationThreadControlRunner(controls,
+                        frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
+                        animationType, mViewRoot.mHandler)
+                : new InsetsAnimationControlImpl(controls,
+                        frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
+                        animationType);
+        mRunningAnimations.add(new RunningAnimation(runner, animationType));
+        if (cancellationSignal != null) {
+            cancellationSignal.setOnCancelListener(runner::cancel);
+        }
+        if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
+            showDirectly(types);
+        } else {
+            hideDirectly(types, false /* animationFinished */, animationType);
+        }
     }
 
     /**
@@ -666,7 +705,7 @@
             }
             final InsetsSourceControl control = consumer.getControl();
             if (control != null) {
-                controls.put(consumer.getType(), control);
+                controls.put(consumer.getType(), new InsetsSourceControl(control));
                 typesReady |= toPublicType(consumer.getType());
             } else if (animationType == ANIMATION_TYPE_SHOW) {
 
@@ -705,7 +744,7 @@
 
     private void cancelExistingControllers(@InsetsType int types) {
         for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
-            InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
+            InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
             if ((control.getTypes() & types) != 0) {
                 cancelAnimation(control, true /* invokeCallback */);
             }
@@ -725,13 +764,13 @@
 
     @VisibleForTesting
     @Override
-    public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
-        cancelAnimation(controller, false /* invokeCallback */);
+    public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
+        cancelAnimation(runner, false /* invokeCallback */);
         if (shown) {
-            showDirectly(controller.getTypes());
+            showDirectly(runner.getTypes());
         } else {
-            hideDirectly(controller.getTypes(), true /* animationFinished */,
-                    controller.getAnimationType());
+            hideDirectly(runner.getTypes(), true /* animationFinished */,
+                    runner.getAnimationType());
         }
     }
 
@@ -756,7 +795,7 @@
 
     void notifyControlRevoked(InsetsSourceConsumer consumer) {
         for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
-            InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
+            InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
             if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
                 cancelAnimation(control, true /* invokeCallback */);
             }
@@ -766,12 +805,12 @@
         }
     }
 
-    private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) {
+    private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
         if (invokeCallback) {
-            control.onCancelled();
+            control.cancel();
         }
         for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
-            if (mRunningAnimations.get(i).control == control) {
+            if (mRunningAnimations.get(i).runner == control) {
                 mRunningAnimations.remove(i);
                 break;
             }
@@ -844,7 +883,7 @@
     @VisibleForTesting
     public @AnimationType int getAnimationType(@InternalInsetsType int type) {
         for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
-            InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
+            InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
             if (control.controlsInternalType(type)) {
                 return mRunningAnimations.get(i).type;
             }
@@ -878,15 +917,25 @@
             return;
         }
 
+        boolean useInsetsAnimationThread = canUseInsetsAnimationThread();
         final InternalAnimationControlListener listener =
-                new InternalAnimationControlListener(show);
+                new InternalAnimationControlListener(show, useInsetsAnimationThread);
         // Show/hide animations always need to be relative to the display frame, in order that shown
         // and hidden state insets are correct.
         controlAnimationUnchecked(
-                types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
+                types, null /* cancellationSignal */, listener, mState.getDisplayFrame(), fromIme,
+                listener.getDurationMs(),
                 INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                 show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
-                        : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
+                        : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
+                useInsetsAnimationThread);
+    }
+
+    private boolean canUseInsetsAnimationThread() {
+        if (mViewRoot.mView == null) {
+            return true;
+        }
+        return !mViewRoot.mView.hasWindowInsetsAnimationCallback();
     }
 
     private void hideDirectly(
@@ -921,13 +970,7 @@
     @Override
     public void startAnimation(InsetsAnimationControlImpl controller,
             WindowInsetsAnimationControlListener listener, int types,
-            WindowInsetsAnimation animation, Bounds bounds, int layoutDuringAnimation) {
-        if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
-            showDirectly(types);
-        } else {
-            hideDirectly(types, false /* animationFinished */, controller.getAnimationType());
-        }
-
+            WindowInsetsAnimation animation, Bounds bounds) {
         if (mViewRoot.mView == null) {
             return;
         }
@@ -941,7 +984,7 @@
                 }
                 for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                     RunningAnimation runningAnimation = mRunningAnimations.get(i);
-                    if (runningAnimation.control == controller) {
+                    if (runningAnimation.runner == controller) {
                         runningAnimation.startDispatched = true;
                     }
                 }
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 252fc0c..3325734 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -117,7 +117,7 @@
             }
         }
         if (lastControl != null) {
-            lastControl.release(mController);
+            lastControl.release(mController::releaseSurfaceControlFromRt);
         }
     }
 
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 75f6eab..f3ec65f 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -22,6 +22,8 @@
 import android.os.Parcelable;
 import android.view.InsetsState.InternalInsetsType;
 
+import java.util.function.Consumer;
+
 /**
  * Represents a parcelable object to allow controlling a single {@link InsetsSource}.
  * @hide
@@ -94,9 +96,9 @@
         dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
     }
 
-    public void release(InsetsController controller) {
+    public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
         if (mLeash != null) {
-            controller.releaseSurfaceControlFromRt(mLeash);
+            surfaceReleaseConsumer.accept(mLeash);
         }
     }
 
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 8ec5df8..18e0132 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -35,6 +35,7 @@
 
 import com.android.internal.R;
 import com.android.internal.widget.CachingIconView;
+import com.android.internal.widget.NotificationExpandButton;
 
 import java.util.ArrayList;
 
@@ -56,7 +57,7 @@
     private OnClickListener mAppOpsListener;
     private HeaderTouchListener mTouchListener = new HeaderTouchListener();
     private LinearLayout mTransferChip;
-    private ImageView mExpandButton;
+    private NotificationExpandButton mExpandButton;
     private CachingIconView mIcon;
     private View mProfileBadge;
     private View mOverlayIcon;
@@ -65,7 +66,6 @@
     private View mAppOps;
     private View mAudiblyAlertedIcon;
     private int mIconColor;
-    private int mOriginalNotificationColor;
     private boolean mExpanded;
     private boolean mShowExpandButtonAtEnd;
     private boolean mShowWorkBadgeAtEnd;
@@ -324,13 +324,8 @@
         return mIconColor;
     }
 
-    @RemotableViewMethod
-    public void setOriginalNotificationColor(int color) {
-        mOriginalNotificationColor = color;
-    }
-
     public int getOriginalNotificationColor() {
-        return mOriginalNotificationColor;
+        return mExpandButton.getOriginalNotificationColor();
     }
 
     @RemotableViewMethod
@@ -371,7 +366,7 @@
             contentDescriptionId = R.string.expand_button_content_description_collapsed;
         }
         mExpandButton.setImageDrawable(getContext().getDrawable(drawableId));
-        mExpandButton.setColorFilter(mOriginalNotificationColor);
+        mExpandButton.setColorFilter(getOriginalNotificationColor());
         mExpandButton.setContentDescription(mContext.getText(contentDescriptionId));
     }
 
diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java
index 7f36418..e8d9bb5 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.CancellationSignal;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.animation.Interpolator;
@@ -60,21 +62,6 @@
     }
 
     @Override
-    public CancellationSignal controlWindowInsetsAnimation(int types, long durationMillis,
-            Interpolator interpolator,
-            WindowInsetsAnimationControlListener listener) {
-        if (mReplayedInsetsController != null) {
-            return mReplayedInsetsController.controlWindowInsetsAnimation(types, durationMillis,
-                    interpolator, listener);
-        } else {
-            listener.onCancelled();
-            CancellationSignal cancellationSignal = new CancellationSignal();
-            cancellationSignal.cancel();
-            return cancellationSignal;
-        }
-    }
-
-    @Override
     public void setSystemBarsAppearance(int appearance, int mask) {
         if (mReplayedInsetsController != null) {
             mReplayedInsetsController.setSystemBarsAppearance(appearance, mask);
@@ -176,6 +163,19 @@
         mReplayedInsetsController = null;
     }
 
+    @Override
+    public void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
+            @Nullable Interpolator interpolator,
+            CancellationSignal cancellationSignal,
+            @NonNull WindowInsetsAnimationControlListener listener) {
+        if (mReplayedInsetsController != null) {
+            mReplayedInsetsController.controlWindowInsetsAnimation(types, durationMillis,
+                    interpolator, cancellationSignal, listener);
+        } else {
+            listener.onCancelled();
+        }
+    }
+
     private interface PendingRequest {
         void replay(InsetsController controller);
     }
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index a3b3f1f..41a3847 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -26,6 +26,8 @@
 import android.os.Parcelable;
 import android.view.accessibility.IAccessibilityEmbeddedConnection;
 
+import java.util.Objects;
+
 /**
  * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
  * will render in to a root SurfaceControl, and receive input based on the SurfaceControl's
@@ -159,7 +161,8 @@
      * @hide
      */
     @TestApi
-    public void addView(@NonNull View view, WindowManager.LayoutParams attrs) {
+    public void setView(@NonNull View view, @NonNull WindowManager.LayoutParams attrs) {
+        Objects.requireNonNull(view);
         mViewRoot.setView(view, attrs, null);
     }
 
@@ -172,11 +175,18 @@
      * @param width The width to layout the View within, in pixels.
      * @param height The height to layout the View within, in pixels.
      */
-    public void addView(@NonNull View view, int width, int height) {
+    public void setView(@NonNull View view, int width, int height) {
         final WindowManager.LayoutParams lp =
                 new WindowManager.LayoutParams(width, height,
                         WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
-        addView(view, lp);
+        setView(view, lp);
+    }
+
+    /**
+     * @return The view passed to setView, or null if none has been passed.
+     */
+    public @Nullable View getView() {
+        return mViewRoot.getView();
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6236e6e..708a094 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3318,7 +3318,7 @@
      * Flag indicating that the view is autofilled
      *
      * @see #isAutofilled()
-     * @see #setAutofilled(boolean)
+     * @see #setAutofilled(boolean, boolean)
      */
     private static final int PFLAG3_IS_AUTOFILLED = 0x10000;
 
@@ -3428,6 +3428,7 @@
      *                         1        PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE
      *                         11       PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK
      *                        1         PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS
+     *                       1          PFLAG4_AUTOFILL_HIDE_HIGHLIGHT
      * |-------|-------|-------|-------|
      */
 
@@ -3470,6 +3471,11 @@
      */
     static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100;
 
+    /**
+     * Flag indicating the field should not have yellow highlight when autofilled.
+     */
+    private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x100;
+
     /* End of masks for mPrivateFlags4 */
 
     /** @hide */
@@ -9170,6 +9176,13 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean hideAutofillHighlight() {
+        return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0;
+    }
+
+    /**
      * Gets the {@link View}'s current autofill value.
      *
      * <p>By default returns {@code null}, but subclasses should override it and return an
@@ -11227,6 +11240,15 @@
     }
 
     /**
+     * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view
+     *         or view tree of the sub-hierarchy {@code false} otherwise.
+     * @hide
+     */
+    public boolean hasWindowInsetsAnimationCallback() {
+        return getListenerInfo().mWindowInsetsAnimationCallback != null;
+    }
+
+    /**
      * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)}
      * when Window Insets animation is being prepared.
      * @param animation current animation
@@ -11741,7 +11763,7 @@
      * @hide
      */
     @TestApi
-    public void setAutofilled(boolean isAutofilled) {
+    public void setAutofilled(boolean isAutofilled, boolean hideHighlight) {
         boolean wasChanged = isAutofilled != isAutofilled();
 
         if (wasChanged) {
@@ -11751,6 +11773,12 @@
                 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED;
             }
 
+            if (hideHighlight) {
+                mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT;
+            } else {
+                mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT;
+            }
+
             invalidate();
         }
     }
@@ -20569,6 +20597,7 @@
 
             state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
             state.mIsAutofilled = isAutofilled();
+            state.mHideHighlight = hideAutofillHighlight();
             state.mAutofillViewId = mAutofillViewId;
             return state;
         }
@@ -20645,7 +20674,7 @@
                 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved;
             }
             if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) {
-                setAutofilled(baseState.mIsAutofilled);
+                setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight);
             }
             if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) {
                 // It can happen that views have the same view id and the restoration path will not
@@ -24078,12 +24107,13 @@
     }
 
     /**
-     * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled.
+     * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless
+     * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled.
      *
      * @param canvas The canvas to draw on
      */
     private void drawAutofilledHighlight(@NonNull Canvas canvas) {
-        if (isAutofilled()) {
+        if (isAutofilled() && !hideAutofillHighlight()) {
             Drawable autofilledHighlight = getAutofilledDrawable();
 
             if (autofilledHighlight != null) {
@@ -28526,6 +28556,7 @@
         int mSavedData;
         String mStartActivityRequestWhoSaved;
         boolean mIsAutofilled;
+        boolean mHideHighlight;
         int mAutofillViewId;
 
         /**
@@ -28549,6 +28580,7 @@
             mSavedData = source.readInt();
             mStartActivityRequestWhoSaved = source.readString();
             mIsAutofilled = source.readBoolean();
+            mHideHighlight = source.readBoolean();
             mAutofillViewId = source.readInt();
         }
 
@@ -28568,6 +28600,7 @@
             out.writeInt(mSavedData);
             out.writeString(mStartActivityRequestWhoSaved);
             out.writeBoolean(mIsAutofilled);
+            out.writeBoolean(mHideHighlight);
             out.writeInt(mAutofillViewId);
         }
 
@@ -29066,8 +29099,33 @@
             mTreeObserver = new ViewTreeObserver(context);
         }
 
+        @Nullable
+        ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
+            if (mContentCaptureManager != null) {
+                return mContentCaptureManager;
+            }
+            mContentCaptureManager = context.getSystemService(ContentCaptureManager.class);
+            return mContentCaptureManager;
+        }
+
+        void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) {
+            if (mContentCaptureManager == null) {
+                return;
+            }
+
+            ArrayList<Object> events = ensureEvents(
+                        mContentCaptureManager.getMainContentCaptureSession());
+            events.add(insets);
+        }
+
         private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session,
                 @NonNull View view, boolean appeared) {
+            ArrayList<Object> events = ensureEvents(session);
+            events.add(appeared ? view : view.getAutofillId());
+        }
+
+        @NonNull
+        private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) {
             if (mContentCaptureEvents == null) {
                 // Most of the time there will be just one session, so intial capacity is 1
                 mContentCaptureEvents = new SparseArray<>(1);
@@ -29079,16 +29137,8 @@
                 events = new ArrayList<>();
                 mContentCaptureEvents.put(sessionId, events);
             }
-            events.add(appeared ? view : view.getAutofillId());
-        }
 
-        @Nullable
-        ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
-            if (mContentCaptureManager != null) {
-                return mContentCaptureManager;
-            }
-            mContentCaptureManager = context.getSystemService(ContentCaptureManager.class);
-            return mContentCaptureManager;
+            return events;
         }
     }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7d4ec3d..e34e84c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7258,6 +7258,34 @@
                 : DISPATCH_MODE_CONTINUE_ON_SUBTREE;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean hasWindowInsetsAnimationCallback() {
+        if (super.hasWindowInsetsAnimationCallback()) {
+            return true;
+        }
+
+        // If we are root-level content view that fits insets, we imitate consuming behavior, so
+        // no child will retrieve window insets animation callback.
+        // See dispatchWindowInsetsAnimationPrepare.
+        boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+                || isFrameworkOptionalFitsSystemWindows();
+        if (isOptionalFitSystemWindows && mAttachInfo != null
+                && mAttachInfo.mContentOnApplyWindowInsetsListener != null) {
+            return false;
+        }
+
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            if (getChildAt(i).hasWindowInsetsAnimationCallback()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public void dispatchWindowInsetsAnimationPrepare(
             @NonNull WindowInsetsAnimation animation) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 26ac4fc..dd34bcb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -81,6 +81,7 @@
 import android.graphics.Color;
 import android.graphics.FrameInfo;
 import android.graphics.HardwareRenderer.FrameDrawingCallback;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -2254,6 +2255,7 @@
             insets = insets.consumeDisplayCutout();
         }
         host.dispatchApplyWindowInsets(insets);
+        mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all()));
         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
     }
 
@@ -3118,6 +3120,8 @@
                         ViewStructure structure = session.newViewStructure(view);
                         view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
                         session.notifyViewAppeared(structure);
+                    } else if (event instanceof Insets) {
+                        mainSession.notifyViewInsetsChanged(sessionId, (Insets) event);
                     } else {
                         Log.w(mTag, "invalid content capture event: " + event);
                     }
diff --git a/core/java/android/view/WindowInsetsAnimationControlListener.java b/core/java/android/view/WindowInsetsAnimationControlListener.java
index 701bd31..faaf920 100644
--- a/core/java/android/view/WindowInsetsAnimationControlListener.java
+++ b/core/java/android/view/WindowInsetsAnimationControlListener.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.annotation.Hide;
 import android.annotation.NonNull;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.inputmethod.EditorInfo;
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index 2ad557e..0282eca 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -156,16 +156,17 @@
      *                     calculate {@link WindowInsetsAnimation#getInterpolatedFraction()}.
      * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
      *                 windows are ready to be controlled, among other callbacks.
-     * @return A cancellation signal that the caller can use to cancel the request to obtain
-     *         control, or once they have control, to cancel the control.
+     * @param cancellationSignal A cancellation signal that the caller can use to cancel the
+     *                           request to obtain control, or once they have control, to cancel the
+     *                           control.
      * @see WindowInsetsAnimation#getFraction()
      * @see WindowInsetsAnimation#getInterpolatedFraction()
      * @see WindowInsetsAnimation#getInterpolator()
      * @see WindowInsetsAnimation#getDurationMillis()
      */
-    @NonNull
-    CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
+    void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
             @Nullable Interpolator interpolator,
+            @Nullable CancellationSignal cancellationSignal,
             @NonNull WindowInsetsAnimationControlListener listener);
 
     /**
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 01a1c77..410d9af 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -504,6 +504,7 @@
     }
 
     void doRemoveView(ViewRootImpl root) {
+        boolean allViewsRemoved;
         synchronized (mLock) {
             final int index = mRoots.indexOf(root);
             if (index >= 0) {
@@ -512,10 +513,17 @@
                 final View view = mViews.remove(index);
                 mDyingViews.remove(view);
             }
+            allViewsRemoved = mRoots.isEmpty();
         }
         if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
             doTrimForeground();
         }
+
+        // If we don't have any views anymore in our process, we no longer need the
+        // InsetsAnimationThread to save some resources.
+        if (allViewsRemoved) {
+            InsetsAnimationThread.release();
+        }
     }
 
     private int findViewLocked(View view, boolean required) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index dda4e8b..39a9ed4 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1236,7 +1236,7 @@
             // If the session is gone some fields might still be highlighted, hence we have to
             // remove the isAutofilled property even if no sessions are active.
             if (mLastAutofilledData == null) {
-                view.setAutofilled(false);
+                view.setAutofilled(false, false);
             } else {
                 id = view.getAutofillId();
                 if (mLastAutofilledData.containsKey(id)) {
@@ -1244,13 +1244,13 @@
                     valueWasRead = true;
 
                     if (Objects.equals(mLastAutofilledData.get(id), value)) {
-                        view.setAutofilled(true);
+                        view.setAutofilled(true, false);
                     } else {
-                        view.setAutofilled(false);
+                        view.setAutofilled(false, false);
                         mLastAutofilledData.remove(id);
                     }
                 } else {
-                    view.setAutofilled(false);
+                    view.setAutofilled(false, false);
                 }
             }
 
@@ -2166,7 +2166,8 @@
      * @param view The view that is to be autofilled
      * @param targetValue The value we want to fill into view
      */
-    private void setAutofilledIfValuesIs(@NonNull View view, @Nullable AutofillValue targetValue) {
+    private void setAutofilledIfValuesIs(@NonNull View view, @Nullable AutofillValue targetValue,
+            boolean hideHighlight) {
         AutofillValue currentValue = view.getAutofillValue();
         if (Objects.equals(currentValue, targetValue)) {
             synchronized (mLock) {
@@ -2175,11 +2176,12 @@
                 }
                 mLastAutofilledData.put(view.getAutofillId(), targetValue);
             }
-            view.setAutofilled(true);
+            view.setAutofilled(true, hideHighlight);
         }
     }
 
-    private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+    private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values,
+            boolean hideHighlight) {
         synchronized (mLock) {
             if (sessionId != mSessionId) {
                 return;
@@ -2238,7 +2240,7 @@
                     // synchronously.
                     // If autofill happens async, the view is set to autofilled in
                     // notifyValueChanged.
-                    setAutofilledIfValuesIs(view, value);
+                    setAutofilledIfValuesIs(view, value, hideHighlight);
 
                     numApplied++;
                 }
@@ -3256,10 +3258,11 @@
         }
 
         @Override
-        public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+        public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values,
+                boolean hideHighlight) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.autofill(sessionId, ids, values));
+                afm.post(() -> afm.autofill(sessionId, ids, values, hideHighlight));
             }
         }
 
@@ -3397,10 +3400,11 @@
         }
 
         @Override
-        public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+        public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values,
+                boolean hideHighlight) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.autofill(sessionId, ids, values));
+                afm.post(() -> afm.autofill(sessionId, ids, values, hideHighlight));
             }
         }
 
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 03054df..8526c1e 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -38,7 +38,8 @@
     /**
      * Autofills the activity with the contents of the values.
      */
-    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
+            boolean hideHighlight);
 
     /**
       * Requests showing the fill UI.
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 3903665..4371b3c 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -44,7 +44,8 @@
     /**
       * Autofills the activity with the contents of a dataset.
       */
-    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
+            boolean hideHighlight);
 
     /**
       * Authenticates a fill response or a data set.
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 7487ec4..44b4353 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Insets;
 import android.view.autofill.AutofillId;
 import android.view.contentcapture.ViewNode.ViewStructureImpl;
 
@@ -84,6 +85,11 @@
     }
 
     @Override
+    void internalNotifyViewInsetsChanged(@NonNull Insets viewInsets) {
+        getMainCaptureSession().notifyViewInsetsChanged(mId, viewInsets);
+    }
+
+    @Override
     public void internalNotifyViewTreeEvent(boolean started) {
         getMainCaptureSession().notifyViewTreeEvent(mId, started);
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index c29d251..ea34d94 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.graphics.Insets;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -112,6 +113,11 @@
      */
     public static final int TYPE_SESSION_PAUSED = 8;
 
+    /**
+     * Called when the view's insets are changed. The new insets associated with the
+     * event may then be retrieved by calling {@link #getInsets()}
+     */
+    public static final int TYPE_VIEW_INSETS_CHANGED = 9;
 
     /** @hide */
     @IntDef(prefix = { "TYPE_" }, value = {
@@ -122,7 +128,8 @@
             TYPE_VIEW_TREE_APPEARED,
             TYPE_CONTEXT_UPDATED,
             TYPE_SESSION_PAUSED,
-            TYPE_SESSION_RESUMED
+            TYPE_SESSION_RESUMED,
+            TYPE_VIEW_INSETS_CHANGED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType{}
@@ -136,6 +143,7 @@
     private @Nullable CharSequence mText;
     private int mParentSessionId = NO_SESSION_ID;
     private @Nullable ContentCaptureContext mClientContext;
+    private @Nullable Insets mInsets;
 
     /** @hide */
     public ContentCaptureEvent(int sessionId, int type, long eventTime) {
@@ -242,6 +250,13 @@
         return this;
     }
 
+    /** @hide */
+    @NonNull
+    public ContentCaptureEvent setInsets(@NonNull Insets insets) {
+        mInsets = insets;
+        return this;
+    }
+
     /**
      * Gets the type of the event.
      *
@@ -305,6 +320,16 @@
     }
 
     /**
+     * Gets the rectangle of the insets associated with the event. Valid insets will only be
+     * returned if the type of the event is {@link #TYPE_VIEW_INSETS_CHANGED}, otherwise they
+     * will be null.
+     */
+    @Nullable
+    public Insets getInsets() {
+        return mInsets;
+    }
+
+    /**
      * Merges event of the same type, either {@link #TYPE_VIEW_TEXT_CHANGED}
      * or {@link #TYPE_VIEW_DISAPPEARED}.
      *
@@ -369,7 +394,9 @@
         }
         if (mClientContext != null) {
             pw.print(", context="); mClientContext.dump(pw); pw.println();
-
+        }
+        if (mInsets != null) {
+            pw.print(", insets="); pw.println(mInsets);
         }
     }
 
@@ -401,6 +428,9 @@
         if (mClientContext != null) {
             string.append(", context=").append(mClientContext);
         }
+        if (mInsets != null) {
+            string.append(", insets=").append(mInsets);
+        }
         return string.append(']').toString();
     }
 
@@ -424,6 +454,9 @@
         if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) {
             parcel.writeParcelable(mClientContext, flags);
         }
+        if (mType == TYPE_VIEW_INSETS_CHANGED) {
+            parcel.writeParcelable(mInsets, flags);
+        }
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureEvent> CREATOR =
@@ -455,6 +488,9 @@
             if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) {
                 event.setClientContext(parcel.readParcelable(null));
             }
+            if (type == TYPE_VIEW_INSETS_CHANGED) {
+                event.setInsets(parcel.readParcelable(null));
+            }
             return event;
         }
 
@@ -488,6 +524,8 @@
                 return "VIEW_TREE_APPEARED";
             case TYPE_CONTEXT_UPDATED:
                 return "CONTEXT_UPDATED";
+            case TYPE_VIEW_INSETS_CHANGED:
+                return "VIEW_INSETS_CHANGED";
             default:
                 return "UKNOWN_TYPE: " + type;
         }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 2134dab..012f5e6 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.graphics.Insets;
 import android.util.DebugUtils;
 import android.util.Log;
 import android.view.View;
@@ -440,6 +441,19 @@
     abstract void internalNotifyViewTextChanged(@NonNull AutofillId id,
             @Nullable CharSequence text);
 
+    /**
+     * Notifies the Intelligence Service that the insets of a view have changed.
+     */
+    public final void notifyViewInsetsChanged(@NonNull Insets viewInsets) {
+        Preconditions.checkNotNull(viewInsets);
+
+        if (!isContentCaptureEnabled()) return;
+
+        internalNotifyViewInsetsChanged(viewInsets);
+    }
+
+    abstract void internalNotifyViewInsetsChanged(@NonNull Insets viewInsets);
+
     /** @hide */
     public abstract void internalNotifyViewTreeEvent(boolean started);
 
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 96f224f..893d38d 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -22,6 +22,7 @@
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_INSETS_CHANGED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING;
@@ -36,6 +37,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.graphics.Insets;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -578,6 +580,11 @@
     }
 
     @Override
+    void internalNotifyViewInsetsChanged(@NonNull Insets viewInsets) {
+        notifyViewInsetsChanged(mId, viewInsets);
+    }
+
+    @Override
     public void internalNotifyViewTreeEvent(boolean started) {
         notifyViewTreeEvent(mId, started);
     }
@@ -642,6 +649,12 @@
     }
 
     /** Public because is also used by ViewRootImpl */
+    public void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
+        sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
+                .setInsets(viewInsets));
+    }
+
+    /** Public because is also used by ViewRootImpl */
     public void notifyViewTreeEvent(int sessionId, boolean started) {
         final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
         sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index 6500613..dd1738a 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import android.annotation.BinderThread;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -94,19 +95,21 @@
     }
 
 
-
     /**
      * Inflates a view with the content of this suggestion at a specific size.
      * The size must be between the {@link InlinePresentationSpec#getMinSize() min size}
      * and the {@link InlinePresentationSpec#getMaxSize() max size} of the presentation
      * spec returned by {@link InlineSuggestionInfo#getPresentationSpec()}.
      *
-     * @param context Context in which to inflate the view.
-     * @param size The size at which to inflate the suggestion.
-     * @param callback Callback for receiving the inflated view.
+     * <p> The caller can attach an {@link View.OnClickListener} and/or an
+     * {@link View.OnLongClickListener} to the view in the {@code callback} to receive click and
+     * long click events on the view.
      *
+     * @param context  Context in which to inflate the view.
+     * @param size     The size at which to inflate the suggestion.
+     * @param callback Callback for receiving the inflated view.
      * @throws IllegalArgumentException If an invalid argument is passed.
-     * @throws IllegalStateException if this method is already called.
+     * @throws IllegalStateException    If this method is already called.
      */
     public void inflate(@NonNull Context context, @NonNull Size size,
             @NonNull @CallbackExecutor Executor callbackExecutor,
@@ -151,12 +154,31 @@
         }
 
         @Override
+        @BinderThread
         public void onContent(SurfaceControlViewHost.SurfacePackage content) {
             final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
             if (callbackImpl != null) {
                 callbackImpl.onContent(content);
             }
         }
+
+        @Override
+        @BinderThread
+        public void onClick() {
+            final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
+            if (callbackImpl != null) {
+                callbackImpl.onClick();
+            }
+        }
+
+        @Override
+        @BinderThread
+        public void onLongClick() {
+            final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
+            if (callbackImpl != null) {
+                callbackImpl.onLongClick();
+            }
+        }
     }
 
     private static final class InlineContentCallbackImpl {
@@ -164,6 +186,7 @@
         private final @NonNull Context mContext;
         private final @NonNull Executor mCallbackExecutor;
         private final @NonNull Consumer<View> mCallback;
+        private @Nullable View mView;
 
         InlineContentCallbackImpl(@NonNull Context context,
                 @NonNull @CallbackExecutor Executor callbackExecutor,
@@ -173,12 +196,27 @@
             mCallback = callback;
         }
 
+        @BinderThread
         public void onContent(SurfaceControlViewHost.SurfacePackage content) {
             if (content == null) {
                 mCallbackExecutor.execute(() -> mCallback.accept(/* view */null));
             } else {
-                mCallbackExecutor.execute(
-                        () -> mCallback.accept(new InlineContentView(mContext, content)));
+                mView = new InlineContentView(mContext, content);
+                mCallbackExecutor.execute(() -> mCallback.accept(mView));
+            }
+        }
+
+        @BinderThread
+        public void onClick() {
+            if (mView != null && mView.hasOnClickListeners()) {
+                mView.callOnClick();
+            }
+        }
+
+        @BinderThread
+        public void onLongClick() {
+            if (mView != null && mView.hasOnLongClickListeners()) {
+                mView.performLongClick();
             }
         }
     }
@@ -201,7 +239,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -360,8 +398,8 @@
     };
 
     @DataClass.Generated(
-            time = 1581929285156L,
-            codegenVersion = "1.0.14",
+            time = 1583889058241L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
             inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic  void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.view.View>)\nprivate synchronized  android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.view.View>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
     @Deprecated
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 6246b50..842ba29 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -21,15 +21,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
-import android.annotation.UserIdInt;
 import android.app.Person;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.text.SpannedString;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
@@ -317,13 +314,9 @@
         @NonNull
         @Hint
         private final List<String> mHints;
-        @Nullable
-        private String mCallingPackageName;
-        @UserIdInt
-        private int mUserId = UserHandle.USER_NULL;
         @NonNull
         private Bundle mExtras;
-        private boolean mUseDefaultTextClassifier;
+        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
         private Request(
                 @NonNull List<Message> conversation,
@@ -345,10 +338,8 @@
             int maxSuggestions = in.readInt();
             List<String> hints = new ArrayList<>();
             in.readStringList(hints);
-            String callingPackageName = in.readString();
-            int userId = in.readInt();
             Bundle extras = in.readBundle();
-            boolean useDefaultTextClassifier = in.readBoolean();
+            SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             Request request = new Request(
                     conversation,
@@ -356,9 +347,7 @@
                     maxSuggestions,
                     hints,
                     extras);
-            request.setCallingPackageName(callingPackageName);
-            request.setUserId(userId);
-            request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+            request.setSystemTextClassifierMetadata(systemTcMetadata);
             return request;
         }
 
@@ -368,10 +357,8 @@
             parcel.writeParcelable(mTypeConfig, flags);
             parcel.writeInt(mMaxSuggestions);
             parcel.writeStringList(mHints);
-            parcel.writeString(mCallingPackageName);
-            parcel.writeInt(mUserId);
             parcel.writeBundle(mExtras);
-            parcel.writeBoolean(mUseDefaultTextClassifier);
+            parcel.writeParcelable(mSystemTcMetadata, flags);
         }
 
         @Override
@@ -421,62 +408,31 @@
         }
 
         /**
-         * Sets the name of the package that is sending this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-        public void setCallingPackageName(@Nullable String callingPackageName) {
-            mCallingPackageName = callingPackageName;
-        }
-
-        /**
          * Returns the name of the package that sent this request.
          * This returns {@code null} if no calling package name is set.
          */
         @Nullable
         public String getCallingPackageName() {
-            return mCallingPackageName;
+            return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
         }
 
         /**
-         * Sets the id of the user that sent this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        void setUserId(@UserIdInt int userId) {
-            mUserId = userId;
-        }
-
-        /**
-         * Returns the id of the user that sent this request.
-         * @hide
-         */
-        @UserIdInt
-        public int getUserId() {
-            return mUserId;
-        }
-
-        /**
-         * Sets whether to use the default text classifier to handle this request.
-         * This will be ignored if it is not the system text classifier to handle this request.
+         * Sets the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-            mUseDefaultTextClassifier = useDefaultTextClassifier;
+        void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcData) {
+            mSystemTcMetadata = systemTcData;
         }
 
         /**
-         * Returns whether to use the default text classifier to handle this request. This
-         * will be ignored if it is not the system text classifier to handle this request.
+         * Returns the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        public boolean getUseDefaultTextClassifier() {
-            return mUseDefaultTextClassifier;
+        @Nullable
+        public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+            return mSystemTcMetadata;
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index e0f29a9..9a54544 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -19,10 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.view.textclassifier.TextClassifier.EntityType;
 import android.view.textclassifier.TextClassifier.WidgetType;
 
@@ -129,7 +127,6 @@
     private String mWidgetType = TextClassifier.WIDGET_TYPE_UNKNOWN;
     private @InvocationMethod int mInvocationMethod;
     @Nullable private String mWidgetVersion;
-    private @UserIdInt int mUserId = UserHandle.USER_NULL;
     @Nullable private String mResultId;
     private long mEventTime;
     private long mDurationSinceSessionStart;
@@ -140,7 +137,7 @@
     private int mEnd;
     private int mSmartStart;
     private int mSmartEnd;
-    private boolean mUseDefaultTextClassifier;
+    @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
     SelectionEvent(
             int start, int end,
@@ -161,6 +158,7 @@
         mEventType = in.readInt();
         mEntityType = in.readString();
         mWidgetVersion = in.readInt() > 0 ? in.readString() : null;
+        // TODO: remove mPackageName once aiai does not need it
         mPackageName = in.readString();
         mWidgetType = in.readString();
         mInvocationMethod = in.readInt();
@@ -175,8 +173,7 @@
         mEnd = in.readInt();
         mSmartStart = in.readInt();
         mSmartEnd = in.readInt();
-        mUserId = in.readInt();
-        mUseDefaultTextClassifier = in.readBoolean();
+        mSystemTcMetadata = in.readParcelable(null);
     }
 
     @Override
@@ -189,6 +186,7 @@
         if (mWidgetVersion != null) {
             dest.writeString(mWidgetVersion);
         }
+        // TODO: remove mPackageName once aiai does not need it
         dest.writeString(mPackageName);
         dest.writeString(mWidgetType);
         dest.writeInt(mInvocationMethod);
@@ -205,8 +203,7 @@
         dest.writeInt(mEnd);
         dest.writeInt(mSmartStart);
         dest.writeInt(mSmartEnd);
-        dest.writeInt(mUserId);
-        dest.writeBoolean(mUseDefaultTextClassifier);
+        dest.writeParcelable(mSystemTcMetadata, flags);
     }
 
     @Override
@@ -409,45 +406,26 @@
      */
     @NonNull
     public String getPackageName() {
-        return mPackageName;
+        return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : "";
     }
 
     /**
-     * Sets the id of this event's user.
-     * <p>
-     * Package-private for SystemTextClassifier's use.
-     */
-    void setUserId(@UserIdInt int userId) {
-        mUserId = userId;
-    }
-
-    /**
-     * Returns the id of this event's user.
-     * @hide
-     */
-    @UserIdInt
-    public int getUserId() {
-        return mUserId;
-    }
-
-    /**
-     * Sets whether to use the default text classifier to handle this request.
-     * This will be ignored if it is not the system text classifier to handle this request.
+     * Sets the information about the {@link SystemTextClassifier} that sent this request.
      *
      * @hide
      */
-    void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-        mUseDefaultTextClassifier = useDefaultTextClassifier;
+    void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcMetadata) {
+        mSystemTcMetadata = systemTcMetadata;
     }
 
     /**
-     * Returns whether to use the default text classifier to handle this request. This
-     * will be ignored if it is not the system text classifier to handle this request.
+     * Returns the information about the {@link SystemTextClassifier} that sent this request.
      *
      * @hide
      */
-    public boolean getUseDefaultTextClassifier() {
-        return mUseDefaultTextClassifier;
+    @Nullable
+    public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+        return mSystemTcMetadata;
     }
 
     /**
@@ -476,7 +454,7 @@
         mPackageName = context.getPackageName();
         mWidgetType = context.getWidgetType();
         mWidgetVersion = context.getWidgetVersion();
-        mUserId = context.getUserId();
+        mSystemTcMetadata = context.getSystemTextClassifierMetadata();
     }
 
     /**
@@ -663,10 +641,9 @@
     @Override
     public int hashCode() {
         return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
-                mWidgetVersion, mPackageName, mUserId, mWidgetType, mInvocationMethod, mResultId,
+                mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mResultId,
                 mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
-                mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd,
-                mUseDefaultTextClassifier);
+                mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mSystemTcMetadata);
     }
 
     @Override
@@ -685,7 +662,6 @@
                 && Objects.equals(mEntityType, other.mEntityType)
                 && Objects.equals(mWidgetVersion, other.mWidgetVersion)
                 && Objects.equals(mPackageName, other.mPackageName)
-                && mUserId == other.mUserId
                 && Objects.equals(mWidgetType, other.mWidgetType)
                 && mInvocationMethod == other.mInvocationMethod
                 && Objects.equals(mResultId, other.mResultId)
@@ -698,7 +674,7 @@
                 && mEnd == other.mEnd
                 && mSmartStart == other.mSmartStart
                 && mSmartEnd == other.mSmartEnd
-                && mUseDefaultTextClassifier == other.mUseDefaultTextClassifier;
+                && mSystemTcMetadata == other.mSystemTcMetadata;
     }
 
     @Override
@@ -706,15 +682,14 @@
         return String.format(Locale.US,
                 "SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, "
                         + "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, "
-                        + "userId=%d, resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
+                        + "resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
                         + "durationSincePreviousEvent=%d, eventIndex=%d,"
                         + "sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d, "
-                        + "mUseDefaultTextClassifier=%b}",
+                        + "systemTcMetadata=%s}",
                 mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
                 mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod,
-                mUserId, mResultId, mEventTime, mDurationSinceSessionStart,
-                mDurationSincePreviousEvent, mEventIndex,
-                mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mUseDefaultTextClassifier);
+                mResultId, mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
+                mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mSystemTcMetadata);
     }
 
     public static final @android.annotation.NonNull Creator<SelectionEvent> CREATOR = new Creator<SelectionEvent>() {
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index fe5e8d6..86ef4e1 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.content.Context;
 import android.os.Bundle;
@@ -39,7 +38,8 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * Proxy to the system's default TextClassifier.
+ * proxy to the request to TextClassifierService via the TextClassificationManagerService.
+ *
  * @hide
  */
 @VisibleForTesting(visibility = Visibility.PACKAGE)
@@ -50,14 +50,19 @@
     private final ITextClassifierService mManagerService;
     private final TextClassificationConstants mSettings;
     private final TextClassifier mFallback;
-    private final String mPackageName;
-    // NOTE: Always set this before sending a request to the manager service otherwise the manager
-    // service will throw a remote exception.
-    @UserIdInt
-    private final int mUserId;
-    private final boolean mUseDefault;
     private TextClassificationSessionId mSessionId;
+    // NOTE: Always set this before sending a request to the manager service otherwise the
+    // manager service will throw a remote exception.
+    @NonNull
+    private final SystemTextClassifierMetadata mSystemTcMetadata;
 
+    /**
+     * Constructor of {@link SystemTextClassifier}
+     *
+     * @param context the context of the request.
+     * @param settings TextClassifier specific settings.
+     * @param useDefault whether to use the default text classifier to handle this request
+     */
     public SystemTextClassifier(
             Context context,
             TextClassificationConstants settings,
@@ -66,9 +71,11 @@
                 ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE));
         mSettings = Objects.requireNonNull(settings);
         mFallback = TextClassifier.NO_OP;
-        mPackageName = Objects.requireNonNull(context.getOpPackageName());
-        mUserId = context.getUserId();
-        mUseDefault = useDefault;
+        // NOTE: Always set this before sending a request to the manager service otherwise the
+        // manager service will throw a remote exception.
+        mSystemTcMetadata = new SystemTextClassifierMetadata(
+                Objects.requireNonNull(context.getOpPackageName()), context.getUserId(),
+                useDefault);
     }
 
     /**
@@ -80,9 +87,7 @@
         Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
-            request.setCallingPackageName(mPackageName);
-            request.setUserId(mUserId);
-            request.setUseDefaultTextClassifier(mUseDefault);
+            request.setSystemTextClassifierMetadata(mSystemTcMetadata);
             final BlockingCallback<TextSelection> callback =
                     new BlockingCallback<>("textselection");
             mManagerService.onSuggestSelection(mSessionId, request, callback);
@@ -105,9 +110,7 @@
         Objects.requireNonNull(request);
         Utils.checkMainThread();
         try {
-            request.setCallingPackageName(mPackageName);
-            request.setUserId(mUserId);
-            request.setUseDefaultTextClassifier(mUseDefault);
+            request.setSystemTextClassifierMetadata(mSystemTcMetadata);
             final BlockingCallback<TextClassification> callback =
                     new BlockingCallback<>("textclassification");
             mManagerService.onClassifyText(mSessionId, request, callback);
@@ -137,9 +140,7 @@
         }
 
         try {
-            request.setCallingPackageName(mPackageName);
-            request.setUserId(mUserId);
-            request.setUseDefaultTextClassifier(mUseDefault);
+            request.setSystemTextClassifierMetadata(mSystemTcMetadata);
             final BlockingCallback<TextLinks> callback =
                     new BlockingCallback<>("textlinks");
             mManagerService.onGenerateLinks(mSessionId, request, callback);
@@ -159,8 +160,7 @@
         Utils.checkMainThread();
 
         try {
-            event.setUserId(mUserId);
-            event.setUseDefaultTextClassifier(mUseDefault);
+            event.setSystemTextClassifierMetadata(mSystemTcMetadata);
             mManagerService.onSelectionEvent(mSessionId, event);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error reporting selection event.", e);
@@ -173,12 +173,11 @@
         Utils.checkMainThread();
 
         try {
-            final TextClassificationContext tcContext = event.getEventContext() == null
-                    ? new TextClassificationContext.Builder(mPackageName, WIDGET_TYPE_UNKNOWN)
-                            .build()
-                    : event.getEventContext();
-            tcContext.setUserId(mUserId);
-            tcContext.setUseDefaultTextClassifier(mUseDefault);
+            final TextClassificationContext tcContext =
+                    event.getEventContext() == null ? new TextClassificationContext.Builder(
+                            mSystemTcMetadata.getCallingPackageName(), WIDGET_TYPE_UNKNOWN).build()
+                            : event.getEventContext();
+            tcContext.setSystemTextClassifierMetadata(mSystemTcMetadata);
             event.setEventContext(tcContext);
             mManagerService.onTextClassifierEvent(mSessionId, event);
         } catch (RemoteException e) {
@@ -192,9 +191,7 @@
         Utils.checkMainThread();
 
         try {
-            request.setCallingPackageName(mPackageName);
-            request.setUserId(mUserId);
-            request.setUseDefaultTextClassifier(mUseDefault);
+            request.setSystemTextClassifierMetadata(mSystemTcMetadata);
             final BlockingCallback<TextLanguage> callback =
                     new BlockingCallback<>("textlanguage");
             mManagerService.onDetectLanguage(mSessionId, request, callback);
@@ -214,9 +211,7 @@
         Utils.checkMainThread();
 
         try {
-            request.setCallingPackageName(mPackageName);
-            request.setUserId(mUserId);
-            request.setUseDefaultTextClassifier(mUseDefault);
+            request.setSystemTextClassifierMetadata(mSystemTcMetadata);
             final BlockingCallback<ConversationActions> callback =
                     new BlockingCallback<>("conversation-actions");
             mManagerService.onSuggestConversationActions(mSessionId, request, callback);
@@ -256,10 +251,8 @@
         printWriter.println("SystemTextClassifier:");
         printWriter.increaseIndent();
         printWriter.printPair("mFallback", mFallback);
-        printWriter.printPair("mPackageName", mPackageName);
         printWriter.printPair("mSessionId", mSessionId);
-        printWriter.printPair("mUserId", mUserId);
-        printWriter.printPair("mUseDefault",  mUseDefault);
+        printWriter.printPair("mSystemTcMetadata",  mSystemTcMetadata);
         printWriter.decreaseIndent();
         printWriter.println();
     }
@@ -275,7 +268,7 @@
             @NonNull TextClassificationSessionId sessionId) {
         mSessionId = Objects.requireNonNull(sessionId);
         try {
-            classificationContext.setUserId(mUserId);
+            classificationContext.setSystemTextClassifierMetadata(mSystemTcMetadata);
             mManagerService.onCreateTextClassificationSession(classificationContext, mSessionId);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error starting a new classification session.", e);
diff --git a/core/java/android/os/incremental/IncrementalSignature.aidl b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.aidl
similarity index 63%
rename from core/java/android/os/incremental/IncrementalSignature.aidl
rename to core/java/android/view/textclassifier/SystemTextClassifierMetadata.aidl
index 729e8e5..4d4e90a 100644
--- a/core/java/android/os/incremental/IncrementalSignature.aidl
+++ b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.aidl
@@ -14,18 +14,6 @@
  * limitations under the License.
  */
 
-package android.os.incremental;
+package android.view.textclassifier;
 
-/** {@hide} */
-parcelable IncrementalSignature {
-    /*
-     * Stable AIDL doesn't support constants, but here's the possible values
-     *   const int HASH_ALGO_NONE = 0;
-     *   const int HASH_ALGO_SHA256 = 1;
-    */
-
-    int hashAlgorithm = 0;
-    byte[] rootHash;
-    byte[] additionalData;
-    byte[] signature;
-}
+parcelable SystemTextClassifierMetadata;
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/SystemTextClassifierMetadata.java b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.java
new file mode 100644
index 0000000..971e3e2
--- /dev/null
+++ b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.java
@@ -0,0 +1,121 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * SystemTextClassifier specific information.
+ * <p>
+ * This contains information requires for the TextClassificationManagerService to process the
+ * requests from the application, e.g. user id, calling package name and etc. Centrialize the data
+ * into this class helps to extend the scalability if we want to add new fields.
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PACKAGE)
+public final class SystemTextClassifierMetadata implements Parcelable {
+
+    /* The name of the package that sent the TC request. */
+    @NonNull
+    private final String mCallingPackageName;
+    /* The id of the user that sent the TC request. */
+    @UserIdInt
+    private final int mUserId;
+    /* Whether to use the default text classifier to handle the request. */
+    private final boolean mUseDefaultTextClassifier;
+
+    public SystemTextClassifierMetadata(@NonNull String packageName, @UserIdInt int userId,
+            boolean useDefaultTextClassifier) {
+        Objects.requireNonNull(packageName);
+        mCallingPackageName = packageName;
+        mUserId = userId;
+        mUseDefaultTextClassifier = useDefaultTextClassifier;
+    }
+
+    /**
+     * Returns the id of the user that sent the TC request.
+     */
+    @UserIdInt
+    public int getUserId() {
+        return mUserId;
+    }
+
+    /**
+     * Returns the name of the package that sent the TC request.
+     * This returns {@code null} if no calling package name is set.
+     */
+    @NonNull
+    public String getCallingPackageName() {
+        return mCallingPackageName;
+    }
+
+    /**
+     * Returns whether to use the default text classifier to handle TC request.
+     */
+    public boolean useDefaultTextClassifier() {
+        return mUseDefaultTextClassifier;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US,
+                "SystemTextClassifierMetadata {callingPackageName=%s, userId=%d, "
+                        + "useDefaultTextClassifier=%b}",
+                mCallingPackageName, mUserId, mUseDefaultTextClassifier);
+    }
+
+    private static SystemTextClassifierMetadata readFromParcel(Parcel in) {
+        final String packageName = in.readString();
+        final int userId = in.readInt();
+        final boolean useDefaultTextClassifier = in.readBoolean();
+        return new SystemTextClassifierMetadata(packageName, userId, useDefaultTextClassifier);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mCallingPackageName);
+        dest.writeInt(mUserId);
+        dest.writeBoolean(mUseDefaultTextClassifier);
+    }
+
+    public static final @NonNull Creator<SystemTextClassifierMetadata> CREATOR =
+            new Creator<SystemTextClassifierMetadata>() {
+        @Override
+        public SystemTextClassifierMetadata createFromParcel(Parcel in) {
+            return readFromParcel(in);
+        }
+
+        @Override
+        public SystemTextClassifierMetadata[] newArray(int size) {
+            return new SystemTextClassifierMetadata[size];
+        }
+    };
+}
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 00f762b..8b9d129 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -21,7 +21,6 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.content.Context;
@@ -36,7 +35,6 @@
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.text.SpannedString;
 import android.util.ArrayMap;
 import android.view.View.OnClickListener;
@@ -552,10 +550,7 @@
         @Nullable private final LocaleList mDefaultLocales;
         @Nullable private final ZonedDateTime mReferenceTime;
         @NonNull private final Bundle mExtras;
-        @Nullable private String mCallingPackageName;
-        @UserIdInt
-        private int mUserId = UserHandle.USER_NULL;
-        private boolean mUseDefaultTextClassifier;
+        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
         private Request(
                 CharSequence text,
@@ -616,62 +611,33 @@
         }
 
         /**
-         * Sets the name of the package that is sending this request.
-         * <p>
-         * For SystemTextClassifier's use.
-         * @hide
-         */
-        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-        public void setCallingPackageName(@Nullable String callingPackageName) {
-            mCallingPackageName = callingPackageName;
-        }
-
-        /**
          * Returns the name of the package that sent this request.
          * This returns {@code null} if no calling package name is set.
          */
         @Nullable
         public String getCallingPackageName() {
-            return mCallingPackageName;
+            return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
         }
 
         /**
-         * Sets the id of the user that sent this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        void setUserId(@UserIdInt int userId) {
-            mUserId = userId;
-        }
-
-        /**
-         * Returns the id of the user that sent this request.
-         * @hide
-         */
-        @UserIdInt
-        public int getUserId() {
-            return mUserId;
-        }
-
-        /**
-         * Sets whether to use the default text classifier to handle this request.
-         * This will be ignored if it is not the system text classifier to handle this request.
+         * Sets the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-            mUseDefaultTextClassifier = useDefaultTextClassifier;
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        public void setSystemTextClassifierMetadata(
+                @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+            mSystemTcMetadata = systemTcMetadata;
         }
 
         /**
-         * Returns whether to use the default text classifier to handle this request. This
-         * will be ignored if it is not the system text classifier to handle this request.
+         * Returns the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        public boolean getUseDefaultTextClassifier() {
-            return mUseDefaultTextClassifier;
+        @Nullable
+        public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+            return mSystemTcMetadata;
         }
 
         /**
@@ -773,10 +739,8 @@
             dest.writeInt(mEndIndex);
             dest.writeParcelable(mDefaultLocales, flags);
             dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
-            dest.writeString(mCallingPackageName);
-            dest.writeInt(mUserId);
             dest.writeBundle(mExtras);
-            dest.writeBoolean(mUseDefaultTextClassifier);
+            dest.writeParcelable(mSystemTcMetadata, flags);
         }
 
         private static Request readFromParcel(Parcel in) {
@@ -787,16 +751,12 @@
             final String referenceTimeString = in.readString();
             final ZonedDateTime referenceTime = referenceTimeString == null
                     ? null : ZonedDateTime.parse(referenceTimeString);
-            final String callingPackageName = in.readString();
-            final int userId = in.readInt();
             final Bundle extras = in.readBundle();
-            final boolean useDefaultTextClassifier = in.readBoolean();
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, startIndex, endIndex,
                     defaultLocales, referenceTime, extras);
-            request.setCallingPackageName(callingPackageName);
-            request.setUserId(userId);
-            request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+            request.setSystemTextClassifierMetadata(systemTcMetadata);
             return request;
         }
 
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
index d58d175..f2323c6 100644
--- a/core/java/android/view/textclassifier/TextClassificationContext.java
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -18,10 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.view.textclassifier.TextClassifier.WidgetType;
 
 import java.util.Locale;
@@ -33,12 +31,11 @@
  */
 public final class TextClassificationContext implements Parcelable {
 
-    private final String mPackageName;
+    // NOTE: Modify packageName only in the constructor or in setSystemTextClassifierMetadata()
+    private String mPackageName;
     private final String mWidgetType;
     @Nullable private final String mWidgetVersion;
-    @UserIdInt
-    private int mUserId = UserHandle.USER_NULL;
-    private boolean mUseDefaultTextClassifier;
+    private SystemTextClassifierMetadata mSystemTcMetadata;
 
     private TextClassificationContext(
             String packageName,
@@ -58,42 +55,26 @@
     }
 
     /**
-     * Sets the id of this context's user.
-     * <p>
-     * Package-private for SystemTextClassifier's use.
+     * Sets the information about the {@link SystemTextClassifier} that sent this request.
+     *
+     * <p><b>NOTE: </b>This will override the value returned in {@link getPackageName()}.
      * @hide
      */
-    void setUserId(@UserIdInt int userId) {
-        mUserId = userId;
+    void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcMetadata) {
+        mSystemTcMetadata = systemTcMetadata;
+        if (mSystemTcMetadata != null) {
+            mPackageName = mSystemTcMetadata.getCallingPackageName();
+        }
     }
 
     /**
-     * Returns the id of this context's user.
-     * @hide
-     */
-    @UserIdInt
-    public int getUserId() {
-        return mUserId;
-    }
-
-    /**
-     * Sets whether to use the default text classifier to handle this request.
-     * This will be ignored if it is not the system text classifier to handle this request.
+     * Returns the information about the {@link SystemTextClassifier} that sent this request.
      *
      * @hide
      */
-    void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-        mUseDefaultTextClassifier = useDefaultTextClassifier;
-    }
-
-    /**
-     * Returns whether to use the default text classifier to handle this request. This
-     * will be ignored if it is not the system text classifier to handle this request.
-     *
-     * @hide
-     */
-    public boolean getUseDefaultTextClassifier() {
-        return mUseDefaultTextClassifier;
+    @Nullable
+    public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+        return mSystemTcMetadata;
     }
 
     /**
@@ -118,8 +99,8 @@
     @Override
     public String toString() {
         return String.format(Locale.US, "TextClassificationContext{"
-                + "packageName=%s, widgetType=%s, widgetVersion=%s, userId=%d}",
-                mPackageName, mWidgetType, mWidgetVersion, mUserId);
+                + "packageName=%s, widgetType=%s, widgetVersion=%s, systemTcMetadata=%s}",
+                mPackageName, mWidgetType, mWidgetVersion, mSystemTcMetadata);
     }
 
     /**
@@ -176,16 +157,14 @@
         parcel.writeString(mPackageName);
         parcel.writeString(mWidgetType);
         parcel.writeString(mWidgetVersion);
-        parcel.writeInt(mUserId);
-        parcel.writeBoolean(mUseDefaultTextClassifier);
+        parcel.writeParcelable(mSystemTcMetadata, flags);
     }
 
     private TextClassificationContext(Parcel in) {
         mPackageName = in.readString();
         mWidgetType = in.readString();
         mWidgetVersion = in.readString();
-        mUserId = in.readInt();
-        mUseDefaultTextClassifier = in.readBoolean();
+        mSystemTcMetadata = in.readParcelable(null);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<TextClassificationContext> CREATOR =
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index 58024dc..1e8253d 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -20,12 +20,10 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -227,10 +225,7 @@
 
         private final CharSequence mText;
         private final Bundle mExtra;
-        @Nullable private String mCallingPackageName;
-        @UserIdInt
-        private int mUserId = UserHandle.USER_NULL;
-        private boolean mUseDefaultTextClassifier;
+        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
         private Request(CharSequence text, Bundle bundle) {
             mText = text;
@@ -246,61 +241,33 @@
         }
 
         /**
-         * Sets the name of the package that is sending this request.
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-        public void setCallingPackageName(@Nullable String callingPackageName) {
-            mCallingPackageName = callingPackageName;
-        }
-
-        /**
          * Returns the name of the package that sent this request.
          * This returns null if no calling package name is set.
          */
         @Nullable
         public String getCallingPackageName() {
-            return mCallingPackageName;
+            return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
         }
 
         /**
-         * Sets the id of the user that sent this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        void setUserId(@UserIdInt int userId) {
-            mUserId = userId;
-        }
-
-        /**
-         * Returns the id of the user that sent this request.
-         * @hide
-         */
-        @UserIdInt
-        public int getUserId() {
-            return mUserId;
-        }
-
-        /**
-         * Sets whether to use the default text classifier to handle this request.
-         * This will be ignored if it is not the system text classifier to handle this request.
+         * Sets the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-            mUseDefaultTextClassifier = useDefaultTextClassifier;
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        public void setSystemTextClassifierMetadata(
+                @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+            mSystemTcMetadata = systemTcMetadata;
         }
 
         /**
-         * Returns whether to use the default text classifier to handle this request. This
-         * will be ignored if it is not the system text classifier to handle this request.
+         * Returns the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        public boolean getUseDefaultTextClassifier() {
-            return mUseDefaultTextClassifier;
+        @Nullable
+        public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+            return mSystemTcMetadata;
         }
 
         /**
@@ -321,23 +288,17 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeCharSequence(mText);
-            dest.writeString(mCallingPackageName);
-            dest.writeInt(mUserId);
             dest.writeBundle(mExtra);
-            dest.writeBoolean(mUseDefaultTextClassifier);
+            dest.writeParcelable(mSystemTcMetadata, flags);
         }
 
         private static Request readFromParcel(Parcel in) {
             final CharSequence text = in.readCharSequence();
-            final String callingPackageName = in.readString();
-            final int userId = in.readInt();
             final Bundle extra = in.readBundle();
-            final boolean useDefaultTextClassifier = in.readBoolean();
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, extra);
-            request.setCallingPackageName(callingPackageName);
-            request.setUserId(userId);
-            request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+            request.setSystemTextClassifierMetadata(systemTcMetadata);
             return request;
         }
 
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index 7430cb3..dea3a90 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -20,13 +20,11 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.text.Spannable;
 import android.text.method.MovementMethod;
 import android.text.style.ClickableSpan;
@@ -340,12 +338,9 @@
         @Nullable private final LocaleList mDefaultLocales;
         @Nullable private final EntityConfig mEntityConfig;
         private final boolean mLegacyFallback;
-        @Nullable private String mCallingPackageName;
         private final Bundle mExtras;
         @Nullable private final ZonedDateTime mReferenceTime;
-        @UserIdInt
-        private int mUserId = UserHandle.USER_NULL;
-        private boolean mUseDefaultTextClassifier;
+        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
         private Request(
                 CharSequence text,
@@ -409,62 +404,33 @@
         }
 
         /**
-         * Sets the name of the package that is sending this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-        public void setCallingPackageName(@Nullable String callingPackageName) {
-            mCallingPackageName = callingPackageName;
-        }
-
-        /**
          * Returns the name of the package that sent this request.
          * This returns {@code null} if no calling package name is set.
          */
         @Nullable
         public String getCallingPackageName() {
-            return mCallingPackageName;
+            return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
         }
 
         /**
-         * Sets the id of the user that sent this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        void setUserId(@UserIdInt int userId) {
-            mUserId = userId;
-        }
-
-        /**
-         * Returns the id of the user that sent this request.
-         * @hide
-         */
-        @UserIdInt
-        public int getUserId() {
-            return mUserId;
-        }
-
-        /**
-         * Sets whether to use the default text classifier to handle this request.
-         * This will be ignored if it is not the system text classifier to handle this request.
+         * Sets the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-            mUseDefaultTextClassifier = useDefaultTextClassifier;
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        public void setSystemTextClassifierMetadata(
+                @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+            mSystemTcMetadata = systemTcMetadata;
         }
 
         /**
-         * Returns whether to use the default text classifier to handle this request. This
-         * will be ignored if it is not the system text classifier to handle this request.
+         * Returns the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        public boolean getUseDefaultTextClassifier() {
-            return mUseDefaultTextClassifier;
+        @Nullable
+        public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+            return mSystemTcMetadata;
         }
 
         /**
@@ -585,30 +551,24 @@
             dest.writeString(mText.toString());
             dest.writeParcelable(mDefaultLocales, flags);
             dest.writeParcelable(mEntityConfig, flags);
-            dest.writeString(mCallingPackageName);
-            dest.writeInt(mUserId);
             dest.writeBundle(mExtras);
             dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
-            dest.writeBoolean(mUseDefaultTextClassifier);
+            dest.writeParcelable(mSystemTcMetadata, flags);
         }
 
         private static Request readFromParcel(Parcel in) {
             final String text = in.readString();
             final LocaleList defaultLocales = in.readParcelable(null);
             final EntityConfig entityConfig = in.readParcelable(null);
-            final String callingPackageName = in.readString();
-            final int userId = in.readInt();
             final Bundle extras = in.readBundle();
             final String referenceTimeString = in.readString();
             final ZonedDateTime referenceTime = referenceTimeString == null
                     ? null : ZonedDateTime.parse(referenceTimeString);
-            final boolean useDefaultTextClassifier = in.readBoolean();
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, defaultLocales, entityConfig,
                     /* legacyFallback= */ true, referenceTime, extras);
-            request.setCallingPackageName(callingPackageName);
-            request.setUserId(userId);
-            request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+            request.setSystemTextClassifierMetadata(systemTcMetadata);
             return request;
         }
 
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 575a072..d8a632d 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -20,12 +20,10 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.text.SpannedString;
 import android.util.ArrayMap;
 import android.view.textclassifier.TextClassifier.EntityType;
@@ -213,10 +211,7 @@
         @Nullable private final LocaleList mDefaultLocales;
         private final boolean mDarkLaunchAllowed;
         private final Bundle mExtras;
-        @Nullable private String mCallingPackageName;
-        @UserIdInt
-        private int mUserId = UserHandle.USER_NULL;
-        private boolean mUseDefaultTextClassifier;
+        @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
         private Request(
                 CharSequence text,
@@ -278,62 +273,33 @@
         }
 
         /**
-         * Sets the name of the package that is sending this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-        public void setCallingPackageName(@Nullable String callingPackageName) {
-            mCallingPackageName = callingPackageName;
-        }
-
-        /**
          * Returns the name of the package that sent this request.
          * This returns {@code null} if no calling package name is set.
          */
         @Nullable
         public String getCallingPackageName() {
-            return mCallingPackageName;
+            return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
         }
 
         /**
-         * Sets the id of the user that sent this request.
-         * <p>
-         * Package-private for SystemTextClassifier's use.
-         * @hide
-         */
-        void setUserId(@UserIdInt int userId) {
-            mUserId = userId;
-        }
-
-        /**
-         * Returns the id of the user that sent this request.
-         * @hide
-         */
-        @UserIdInt
-        public int getUserId() {
-            return mUserId;
-        }
-
-        /**
-         * Sets whether to use the default text classifier to handle this request.
-         * This will be ignored if it is not the system text classifier to handle this request.
+         * Sets the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
-            mUseDefaultTextClassifier = useDefaultTextClassifier;
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+        public void setSystemTextClassifierMetadata(
+                @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+            mSystemTcMetadata = systemTcMetadata;
         }
 
         /**
-         * Returns whether to use the default text classifier to handle this request. This
-         * will be ignored if it is not the system text classifier to handle this request.
+         * Returns the information about the {@link SystemTextClassifier} that sent this request.
          *
          * @hide
          */
-        public boolean getUseDefaultTextClassifier() {
-            return mUseDefaultTextClassifier;
+        @Nullable
+        public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+            return mSystemTcMetadata;
         }
 
         /**
@@ -438,10 +404,8 @@
             dest.writeInt(mStartIndex);
             dest.writeInt(mEndIndex);
             dest.writeParcelable(mDefaultLocales, flags);
-            dest.writeString(mCallingPackageName);
-            dest.writeInt(mUserId);
             dest.writeBundle(mExtras);
-            dest.writeBoolean(mUseDefaultTextClassifier);
+            dest.writeParcelable(mSystemTcMetadata, flags);
         }
 
         private static Request readFromParcel(Parcel in) {
@@ -449,16 +413,12 @@
             final int startIndex = in.readInt();
             final int endIndex = in.readInt();
             final LocaleList defaultLocales = in.readParcelable(null);
-            final String callingPackageName = in.readString();
-            final int userId = in.readInt();
             final Bundle extras = in.readBundle();
-            final boolean systemTextClassifierType = in.readBoolean();
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, startIndex, endIndex, defaultLocales,
                     /* darkLaunchAllowed= */ false, extras);
-            request.setCallingPackageName(callingPackageName);
-            request.setUserId(userId);
-            request.setUseDefaultTextClassifier(systemTextClassifierType);
+            request.setSystemTextClassifierMetadata(systemTcMetadata);
             return request;
         }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 01a0e9b..7f6c0d2 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2818,7 +2818,7 @@
 
     /**
      * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
-     * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
+     * costly to set PendingIntents on the individual items, and is hence not recommended. Instead
      * this method should be used to set a single PendingIntent template on the collection, and
      * individual items can differentiate their on-click behavior using
      * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
@@ -2834,7 +2834,7 @@
 
     /**
      * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
-     * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
+     * costly to set PendingIntents on the individual items, and is hence not recommended. Instead
      * a single PendingIntent template can be set on the collection, see {@link
      * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the individual on-click
      * action of a given item can be distinguished by setting a fillInIntent on that item. The
@@ -3960,7 +3960,7 @@
 
         /**
          * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is
-         * very costly to set PendingIntents on the individual items, and is hence not permitted.
+         * very costly to set PendingIntents on the individual items, and is hence not recommended.
          * Instead a single PendingIntent template can be set on the collection, see {@link
          * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the individual on-click
          * action of a given item can be distinguished by setting a fillInIntent on that item. The
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index fa567f2..ec2653f 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.stats.devicepolicy.DevicePolicyEnums;
@@ -90,7 +91,9 @@
 
             @Override
             public void requestQuietModeEnabled(boolean enabled, UserHandle workProfileUserHandle) {
-                userManager.requestQuietModeEnabled(enabled, workProfileUserHandle);
+                AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
+                    userManager.requestQuietModeEnabled(enabled, workProfileUserHandle);
+                });
                 mIsWaitingToEnableWorkProfile = true;
             }
         };
@@ -284,7 +287,7 @@
     }
 
     private int userHandleToPageIndex(UserHandle userHandle) {
-        if (userHandle == getPersonalListAdapter().mResolverListController.getUserHandle()) {
+        if (userHandle.equals(getPersonalListAdapter().mResolverListController.getUserHandle())) {
             return PROFILE_PERSONAL;
         } else {
             return PROFILE_WORK;
@@ -293,7 +296,7 @@
 
     private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
         UserHandle listUserHandle = activeListAdapter.getUserHandle();
-        if (listUserHandle == mWorkProfileUserHandle
+        if (listUserHandle.equals(mWorkProfileUserHandle)
                 && mInjector.isQuietModeEnabled(mWorkProfileUserHandle)) {
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
@@ -311,7 +314,7 @@
         if (UserHandle.myUserId() != listUserHandle.getIdentifier()) {
             if (!mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
                     UserHandle.myUserId(), listUserHandle.getIdentifier())) {
-                if (listUserHandle == mPersonalProfileUserHandle) {
+                if (listUserHandle.equals(mPersonalProfileUserHandle)) {
                     DevicePolicyEventLogger.createEvent(
                                 DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
                             .setStrings(getMetricsCategory())
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index eb74612..e0bbc04 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -221,6 +221,12 @@
      */
     abstract float getScore(ComponentName name);
 
+    /**
+     * Returns the list of top K component names which have highest
+     * {@link #getScore(ComponentName)}
+     */
+    abstract List<ComponentName> getTopComponentNames(int topK);
+
     /** Handles result message sent to mHandler. */
     abstract void handleResultMessage(Message message);
 
diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
index 04ad7e9..ba8c7b3 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -36,7 +36,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
 
 /**
  * Uses an {@link AppPredictor} to sort Resolver targets. If the AppPredictionService appears to be
@@ -160,6 +162,15 @@
     }
 
     @Override
+    List<ComponentName> getTopComponentNames(int topK) {
+        return mTargetRanks.entrySet().stream()
+                .sorted(Entry.comparingByValue())
+                .limit(topK)
+                .map(Entry::getKey)
+                .collect(Collectors.toList());
+    }
+
+    @Override
     void updateModel(ComponentName componentName) {
         if (mResolverRankerService != null) {
             mResolverRankerService.updateModel(componentName);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5620bff..3696c83 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -223,6 +223,11 @@
             SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
             DEFAULT_SALT_EXPIRATION_DAYS);
 
+    private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean(
+            DeviceConfig.NAMESPACE_SYSTEMUI,
+            SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
+            false);
+
     private Bundle mReplacementExtras;
     private IntentSender mChosenComponentSender;
     private IntentSender mRefinementIntentSender;
@@ -409,6 +414,11 @@
         private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 10000;
         private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 3000;
 
+        private static final int DEFAULT_DIRECT_SHARE_TIMEOUT_MILLIS = 1500;
+        private int mDirectShareTimeout = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
+                SystemUiDeviceConfigFlags.SHARE_SHEET_DIRECT_SHARE_TIMEOUT,
+                DEFAULT_DIRECT_SHARE_TIMEOUT_MILLIS);
+
         private boolean mMinTimeoutPassed = false;
 
         private void removeAllMessages() {
@@ -427,15 +437,14 @@
 
             if (DEBUG) {
                 Log.d(TAG, "queryTargets setting watchdog timer for "
-                        + WATCHDOG_TIMEOUT_MIN_MILLIS + "-"
+                        + mDirectShareTimeout + "-"
                         + WATCHDOG_TIMEOUT_MAX_MILLIS + "ms");
             }
 
             sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT,
                     WATCHDOG_TIMEOUT_MIN_MILLIS);
             sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT,
-                    WATCHDOG_TIMEOUT_MAX_MILLIS);
-
+                    mAppendDirectShareEnabled ? mDirectShareTimeout : WATCHDOG_TIMEOUT_MAX_MILLIS);
         }
 
         private void maybeStopServiceRequestTimer() {
@@ -463,6 +472,7 @@
                     final ServiceResultInfo sri = (ServiceResultInfo) msg.obj;
                     if (!mServiceConnections.contains(sri.connection)) {
                         Log.w(TAG, "ChooserTargetServiceConnection " + sri.connection
+                                + sri.originalTarget.getResolveInfo().activityInfo.packageName
                                 + " returned after being removed from active connections."
                                 + " Have you considered returning results faster?");
                         break;
@@ -474,7 +484,7 @@
                         if (adapterForUserHandle != null) {
                             adapterForUserHandle.addServiceResults(sri.originalTarget,
                                     sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET,
-                                    /* directShareShortcutInfoCache */ null);
+                                    /* directShareShortcutInfoCache */ null, mServiceConnections);
                         }
                     }
                     unbindService(sri.connection);
@@ -489,6 +499,7 @@
                     break;
 
                 case CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT:
+                    mMinTimeoutPassed = true;
                     unbindRemainingServices();
                     maybeStopServiceRequestTimer();
                     break;
@@ -513,7 +524,7 @@
                         if (adapterForUserHandle != null) {
                             adapterForUserHandle.addServiceResults(
                                     resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1,
-                                    mDirectShareShortcutInfoCache);
+                                    mDirectShareShortcutInfoCache, mServiceConnections);
                         }
                     }
                     break;
@@ -1481,7 +1492,7 @@
                     /* origTarget */ null,
                     Lists.newArrayList(mCallerChooserTargets),
                     TARGET_TYPE_DEFAULT,
-                    /* directShareShortcutInfoCache */ null);
+                    /* directShareShortcutInfoCache */ null, mServiceConnections);
         }
     }
 
@@ -2129,7 +2140,7 @@
             return null;
         }
 
-        if (getPersonalProfileUserHandle() == userHandle) {
+        if (getPersonalProfileUserHandle().equals(userHandle)) {
             if (mPersonalAppPredictor != null) {
                 return mPersonalAppPredictor;
             }
@@ -2155,7 +2166,7 @@
                         .getSystemService(AppPredictionManager.class);
         AppPredictor appPredictionSession = appPredictionManager.createAppPredictionSession(
                 appPredictionContext);
-        if (getPersonalProfileUserHandle() == userHandle) {
+        if (getPersonalProfileUserHandle().equals(userHandle)) {
             mPersonalAppPredictor = appPredictionSession;
         } else {
             mWorkAppPredictor = appPredictionSession;
@@ -2555,7 +2566,7 @@
 
         ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter;
         if (chooserListAdapter.getUserHandle()
-                == mChooserMultiProfilePagerAdapter.getCurrentUserHandle()) {
+                .equals(mChooserMultiProfilePagerAdapter.getCurrentUserHandle())) {
             mChooserMultiProfilePagerAdapter.getActiveAdapterView()
                     .setAdapter(mChooserMultiProfilePagerAdapter.getCurrentRootAdapter());
             mChooserMultiProfilePagerAdapter
@@ -3584,6 +3595,10 @@
                     ? mOriginalTarget.getResolveInfo().activityInfo.toString()
                     : "<connection destroyed>") + "}";
         }
+
+        public ComponentName getComponentName() {
+            return mOriginalTarget.getResolveInfo().activityInfo.getComponentName();
+        }
     }
 
     static class ServiceResultInfo {
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 74ae291..0ea855a 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -32,8 +32,10 @@
 import android.os.AsyncTask;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.service.chooser.ChooserTarget;
 import android.util.Log;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -44,17 +46,26 @@
 import com.android.internal.app.chooser.MultiDisplayResolveInfo;
 import com.android.internal.app.chooser.SelectableTargetInfo;
 import com.android.internal.app.chooser.TargetInfo;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 public class ChooserListAdapter extends ResolverListAdapter {
     private static final String TAG = "ChooserListAdapter";
     private static final boolean DEBUG = false;
 
+    private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean(
+            DeviceConfig.NAMESPACE_SYSTEMUI,
+            SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
+            false);
+
     private boolean mEnableStackedApps = true;
 
     public static final int NO_POSITION = -1;
@@ -84,6 +95,11 @@
     // Reserve spots for incoming direct share targets by adding placeholders
     private ChooserTargetInfo
             mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo();
+    private int mValidServiceTargetsNum = 0;
+    private final Map<ComponentName, Pair<List<ChooserTargetInfo>, Integer>>
+            mParkingDirectShareTargets = new HashMap<>();
+    private Set<ComponentName> mPendingChooserTargetService = new HashSet<>();
+    private Set<ComponentName> mShortcutComponents = new HashSet<>();
     private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
     private final List<TargetInfo> mCallerTargets = new ArrayList<>();
 
@@ -189,6 +205,9 @@
 
     void refreshListView() {
         if (mListViewDataChanged) {
+            if (mAppendDirectShareEnabled) {
+                appendServiceTargetsWithQuota();
+            }
             super.notifyDataSetChanged();
         }
         mListViewDataChanged = false;
@@ -198,6 +217,10 @@
     private void createPlaceHolders() {
         mNumShortcutResults = 0;
         mServiceTargets.clear();
+        mValidServiceTargetsNum = 0;
+        mParkingDirectShareTargets.clear();
+        mPendingChooserTargetService.clear();
+        mShortcutComponents.clear();
         for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
             mServiceTargets.add(mPlaceHolderTargetInfo);
         }
@@ -393,12 +416,19 @@
      */
     public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
             @ChooserActivity.ShareTargetType int targetType,
-            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos) {
+            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos,
+            List<ChooserActivity.ChooserTargetServiceConnection>
+                    pendingChooserTargetServiceConnections) {
         if (DEBUG) {
-            Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
+            Log.d(TAG, "addServiceResults " + origTarget.getResolvedComponentName() + ", "
+                    + targets.size()
                     + " targets");
         }
-
+        if (mAppendDirectShareEnabled) {
+            parkTargetIntoMemory(origTarget, targets, targetType, directShareToShortcutInfos,
+                    pendingChooserTargetServiceConnections);
+            return;
+        }
         if (targets.size() == 0) {
             return;
         }
@@ -449,6 +479,126 @@
         }
     }
 
+    /**
+     * Park {@code targets} into memory for the moment to surface them later when view is refreshed.
+     * Components pending on ChooserTargetService query are also recorded.
+     */
+    private void parkTargetIntoMemory(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
+            @ChooserActivity.ShareTargetType int targetType,
+            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos,
+            List<ChooserActivity.ChooserTargetServiceConnection>
+                    pendingChooserTargetServiceConnections) {
+        ComponentName origComponentName = origTarget.getResolvedComponentName();
+        mPendingChooserTargetService = pendingChooserTargetServiceConnections.stream()
+                .map(ChooserActivity.ChooserTargetServiceConnection::getComponentName)
+                .filter(componentName -> !componentName.equals(origComponentName))
+                .collect(Collectors.toSet());
+        // Park targets in memory
+        if (!targets.isEmpty() && !mParkingDirectShareTargets.containsKey(origComponentName)) {
+            final boolean isShortcutResult =
+                    (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
+                            || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
+            Context contextAsUser = mContext.createContextAsUser(getUserHandle(),
+                    0 /* flags */);
+            List<ChooserTargetInfo> parkingTargetInfos = targets.stream()
+                    .map(target ->
+                            new SelectableTargetInfo(
+                                    contextAsUser, origTarget, target, target.getScore(),
+                                    mSelectableTargetInfoComunicator,
+                                    (isShortcutResult ? directShareToShortcutInfos.get(target)
+                                            : null))
+                    )
+                    .collect(Collectors.toList());
+            mParkingDirectShareTargets.put(origComponentName,
+                    new Pair<>(parkingTargetInfos, 0));
+            if (isShortcutResult) {
+                mShortcutComponents.add(origComponentName);
+            }
+        }
+        notifyDataSetChanged();
+    }
+
+    /**
+     * Append targets of top ranked share app into direct share row with quota limit. Remove
+     * appended ones from memory.
+     */
+    private void appendServiceTargetsWithQuota() {
+        int maxRankedTargets = mChooserListCommunicator.getMaxRankedTargets();
+        List<ComponentName> topComponentNames = getTopComponentNames(maxRankedTargets);
+        int appRank = 0;
+        for (ComponentName component : topComponentNames) {
+            if (!mPendingChooserTargetService.contains(component)
+                    && !mParkingDirectShareTargets.containsKey(component)) {
+                continue;
+            }
+            appRank++;
+            Pair<List<ChooserTargetInfo>, Integer> parkingTargetsItem =
+                    mParkingDirectShareTargets.get(component);
+            if (parkingTargetsItem != null && parkingTargetsItem.second == 0) {
+                List<ChooserTargetInfo> parkingTargets = parkingTargetsItem.first;
+                int initTargetsQuota = appRank <= maxRankedTargets / 2 ? 2 : 1;
+                int insertedNum = 0;
+                while (insertedNum < initTargetsQuota && !parkingTargets.isEmpty()) {
+                    if (!checkDuplicateTarget(parkingTargets.get(0))) {
+                        mServiceTargets.add(mValidServiceTargetsNum, parkingTargets.get(0));
+                        mValidServiceTargetsNum++;
+                        insertedNum++;
+                    }
+                    parkingTargets.remove(0);
+                }
+                mParkingDirectShareTargets.put(component, new Pair<>(parkingTargets, insertedNum));
+                if (mShortcutComponents.contains(component)) {
+                    mNumShortcutResults += insertedNum;
+                }
+            }
+        }
+    }
+
+    /**
+     * Append all remaining targets (parking in memory) into direct share row as per their ranking.
+     */
+    private void fillAllServiceTargets() {
+        int maxRankedTargets = mChooserListCommunicator.getMaxRankedTargets();
+        List<ComponentName> topComponentNames = getTopComponentNames(maxRankedTargets);
+        // Append all remaining targets of top recommended components into direct share row.
+        for (ComponentName component : topComponentNames) {
+            if (!mParkingDirectShareTargets.containsKey(component)) {
+                continue;
+            }
+            mParkingDirectShareTargets.get(component).first.stream()
+                    .filter(target -> !checkDuplicateTarget(target))
+                    .forEach(target -> {
+                        if (mShortcutComponents.contains(component)) {
+                            mNumShortcutResults++;
+                        }
+                        mServiceTargets.add(target);
+                    });
+            mParkingDirectShareTargets.remove(component);
+        }
+        // Append all remaining shortcuts targets into direct share row.
+        List<ChooserTargetInfo> remainingTargets = new ArrayList<>();
+        mParkingDirectShareTargets.entrySet().stream()
+                .filter(entry -> mShortcutComponents.contains(entry.getKey()))
+                .map(entry -> entry.getValue())
+                .map(pair -> pair.first)
+                .forEach(remainingTargets::addAll);
+        remainingTargets.sort(
+                (t1, t2) -> -Float.compare(t1.getModifiedScore(), t2.getModifiedScore()));
+        mServiceTargets.addAll(remainingTargets);
+        mNumShortcutResults += remainingTargets.size();
+        mParkingDirectShareTargets.clear();
+    }
+
+    private boolean checkDuplicateTarget(ChooserTargetInfo chooserTargetInfo) {
+        // Check for duplicates and abort if found
+        for (ChooserTargetInfo otherTargetInfo : mServiceTargets) {
+            if (chooserTargetInfo.isSimilar(otherTargetInfo)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     int getNumShortcutResults() {
         return mNumShortcutResults;
     }
@@ -487,7 +637,9 @@
      */
     public void completeServiceTargetLoading() {
         mServiceTargets.removeIf(o -> o instanceof ChooserActivity.PlaceHolderTargetInfo);
-
+        if (mAppendDirectShareEnabled) {
+            fillAllServiceTargets();
+        }
         if (mServiceTargets.isEmpty()) {
             mServiceTargets.add(new ChooserActivity.EmptyTargetInfo());
         }
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 2167b1e..c6a00f3 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -93,10 +93,10 @@
     @Override
     @Nullable
     ChooserListAdapter getListAdapterForUserHandle(UserHandle userHandle) {
-        if (getActiveListAdapter().getUserHandle() == userHandle) {
+        if (getActiveListAdapter().getUserHandle().equals(userHandle)) {
             return getActiveListAdapter();
         } else if (getInactiveListAdapter() != null
-                && getInactiveListAdapter().getUserHandle() == userHandle) {
+                && getInactiveListAdapter().getUserHandle().equals(userHandle)) {
             return getInactiveListAdapter();
         }
         return null;
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 907ea55..9218823 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -34,14 +34,14 @@
     // be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h
     // and not be reordered
     int checkOperation(int code, int uid, String packageName);
-    int noteOperation(int code, int uid, String packageName, @nullable String featureId,
+    int noteOperation(int code, int uid, String packageName, @nullable String attributionTag,
             boolean shouldCollectAsyncNotedOp, String message);
     int startOperation(IBinder clientId, int code, int uid, String packageName,
-            @nullable String featureId, boolean startIfModeDefault,
+            @nullable String attributionTag, boolean startIfModeDefault,
             boolean shouldCollectAsyncNotedOp, String message);
     @UnsupportedAppUsage
     void finishOperation(IBinder clientId, int code, int uid, String packageName,
-            @nullable String featureId);
+            @nullable String attributionTag);
     void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
     void stopWatchingMode(IAppOpsCallback callback);
     int permissionToOpCode(String permission);
@@ -52,8 +52,8 @@
     // Any new method exposed to native must be added after the last one, do not reorder
 
     int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
-            String proxiedFeatureId, int proxyUid, String proxyPackageName,
-            String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message);
+            String proxiedAttributionTag, int proxyUid, String proxyPackageName,
+            String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message);
 
     // Remaining methods are only used in Java.
     int checkPackage(int uid, String packageName);
@@ -64,10 +64,10 @@
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     @UnsupportedAppUsage
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
-    void getHistoricalOps(int uid, String packageName, String featureId, in List<String> ops,
+    void getHistoricalOps(int uid, String packageName, String attributionTag, in List<String> ops,
             int filter, long beginTimeMillis, long endTimeMillis, int flags,
             in RemoteCallback callback);
-    void getHistoricalOpsFromDiskRaw(int uid, String packageName, String featureId,
+    void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
             in List<String> ops, int filter, long beginTimeMillis, long endTimeMillis, int flags,
             in RemoteCallback callback);
     void offsetHistory(long duration);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ec371d9..086a718 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1242,12 +1242,12 @@
     }
 
     private void maybeLogCrossProfileTargetLaunch(TargetInfo cti, UserHandle currentUserHandle) {
-        if (!hasWorkProfile() || currentUserHandle == getUser()) {
+        if (!hasWorkProfile() || currentUserHandle.equals(getUser())) {
             return;
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.RESOLVER_CROSS_PROFILE_TARGET_OPENED)
-                .setBoolean(currentUserHandle == getPersonalProfileUserHandle())
+                .setBoolean(currentUserHandle.equals(getPersonalProfileUserHandle()))
                 .setStrings(getMetricsCategory(),
                         cti instanceof ChooserTargetInfo ? "direct_share" : "other_target")
                 .write();
@@ -1486,7 +1486,8 @@
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.RESOLVER_AUTOLAUNCH_CROSS_PROFILE_TARGET)
-                .setBoolean(activeListAdapter.getUserHandle() == getPersonalProfileUserHandle())
+                .setBoolean(activeListAdapter.getUserHandle()
+                        .equals(getPersonalProfileUserHandle()))
                 .setStrings(getMetricsCategory())
                 .write();
         safelyStartActivity(activeProfileTarget);
@@ -1778,7 +1779,7 @@
     @Override // ResolverListCommunicator
     public void onHandlePackagesChanged(ResolverListAdapter listAdapter) {
         if (listAdapter == mMultiProfilePagerAdapter.getActiveListAdapter()) {
-            if (listAdapter.getUserHandle() == getWorkProfileUserHandle()
+            if (listAdapter.getUserHandle().equals(getWorkProfileUserHandle())
                     && mMultiProfilePagerAdapter.isWaitingToEnableWorkProfile()) {
                 // We have just turned on the work profile and entered the pass code to start it,
                 // now we are waiting to receive the ACTION_USER_UNLOCKED broadcast. There is no
@@ -1819,7 +1820,7 @@
                     mMultiProfilePagerAdapter.markWorkProfileEnabledBroadcastReceived();
                 }
                 if (mMultiProfilePagerAdapter.getCurrentUserHandle()
-                        == getWorkProfileUserHandle()) {
+                        .equals(getWorkProfileUserHandle())) {
                     mMultiProfilePagerAdapter.rebuildActiveTab(true);
                 } else {
                     mMultiProfilePagerAdapter.clearInactiveProfileCache();
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 61a404e..579abee 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -153,6 +153,14 @@
         return mResolverListController.getScore(target);
     }
 
+    /**
+     * Returns the list of top K component names which have highest
+     * {@link #getScore(DisplayResolveInfo)}
+     */
+    public List<ComponentName> getTopComponentNames(int topK) {
+        return mResolverListController.getTopComponentNames(topK);
+    }
+
     public void updateModel(ComponentName componentName) {
         mResolverListController.updateModel(componentName);
     }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 022aded..51dce55 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -367,6 +367,14 @@
         return mResolverComparator.getScore(target.getResolvedComponentName());
     }
 
+    /**
+     * Returns the list of top K component names which have highest
+     * {@link #getScore(DisplayResolveInfo)}
+     */
+    public List<ComponentName> getTopComponentNames(int topK) {
+        return mResolverComparator.getTopComponentNames(topK);
+    }
+
     public void updateModel(ComponentName componentName) {
         mResolverComparator.updateModel(componentName);
     }
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 0440f5e..578f6ae 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -103,10 +103,10 @@
     @Override
     @Nullable
     ResolverListAdapter getListAdapterForUserHandle(UserHandle userHandle) {
-        if (getActiveListAdapter().getUserHandle() == userHandle) {
+        if (getActiveListAdapter().getUserHandle().equals(userHandle)) {
             return getActiveListAdapter();
         } else if (getInactiveListAdapter() != null
-                && getInactiveListAdapter().getUserHandle() == userHandle) {
+                && getInactiveListAdapter().getUserHandle().equals(userHandle)) {
             return getInactiveListAdapter();
         }
         return null;
diff --git a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
index 01e06220..2869450 100644
--- a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
@@ -48,6 +48,7 @@
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * Ranks and compares packages based on usage stats and uses the {@link ResolverRankerService}.
@@ -252,6 +253,15 @@
         return 0;
     }
 
+    @Override
+    List<ComponentName> getTopComponentNames(int topK) {
+        return mTargetsDict.entrySet().stream()
+                .sorted((o1, o2) -> -Float.compare(getScore(o1.getKey()), getScore(o2.getKey())))
+                .limit(topK)
+                .map(Map.Entry::getKey)
+                .collect(Collectors.toList());
+    }
+
     // update ranking model when the connection to it is valid.
     @Override
     public void updateModel(ComponentName componentName) {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 086b9d8..837cc46 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -378,6 +378,17 @@
             "nav_bar_handle_show_over_lockscreen";
 
     /**
+     * (int) Timeout threshold, in millisecond, that Sharesheet waits for direct share targets.
+     */
+    public static final String SHARE_SHEET_DIRECT_SHARE_TIMEOUT =
+            "share_sheet_direct_share_timeout";
+
+    /**
+     * (boolean) Whether append direct share on Sharesheet is enabled.
+     */
+    public static final String APPEND_DIRECT_SHARE_ENABLED = "append_direct_share_enabled";
+
+    /**
      * (boolean) Whether to enable user-drag resizing for PIP.
      */
     public static final String PIP_USER_RESIZE = "pip_user_resize";
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 94924a5..ff03f1a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -140,6 +140,33 @@
      */
     public static final int MEMORY_TAG_LEVEL_SYNC = 3 << 19;
 
+    /**
+     * A two-bit field for GWP-ASan level of this process. See the possible values below.
+     */
+    public static final int GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22);
+
+    /**
+     * Disable GWP-ASan in this process.
+     * GWP-ASan is a low-overhead memory bug detector using guard pages on a small
+     * subset of heap allocations.
+     */
+    public static final int GWP_ASAN_LEVEL_NEVER = 0 << 21;
+
+    /**
+     * Enable GWP-ASan in this process with a small sampling rate.
+     * With approx. 1% chance GWP-ASan will be activated and apply its protection
+     * to a small subset of heap allocations.
+     * Otherwise (~99% chance) this process is unaffected.
+     */
+    public static final int GWP_ASAN_LEVEL_LOTTERY = 1 << 21;
+
+    /**
+     * Always enable GWP-ASan in this process.
+     * GWP-ASan is activated unconditionally (but still, only a small subset of
+     * allocations is protected).
+     */
+    public static final int GWP_ASAN_LEVEL_ALWAYS = 2 << 21;
+
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
     /** Default external storage should be mounted. */
@@ -178,6 +205,9 @@
     /** List of packages with the same uid, and its app data info: volume uuid and inode. */
     public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
 
+    /** Bind mount app storage dirs to lower fs not via fuse */
+    public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
+
     /**
      * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
      * in the abstract socket namespace. This socket name is what the new child zygote
@@ -283,6 +313,7 @@
      * @param isTopApp true if the process is for top (high priority) application.
      * @param pkgDataInfoList A list that stores related packages and its app data
      * info: volume uuid and inode.
+     * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
      *
      * @return 0 if this is the child, pid of the child
      * if this is the parent, or -1 on error.
@@ -290,13 +321,13 @@
     static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
-            boolean isTopApp, String[] pkgDataInfoList) {
+            boolean isTopApp, String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
         ZygoteHooks.preFork();
 
         int pid = nativeForkAndSpecialize(
                 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                 fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
-                pkgDataInfoList);
+                pkgDataInfoList, bindMountAppStorageDirs);
         if (pid == 0) {
             // Note that this event ends at the end of handleChildProc,
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -312,7 +343,8 @@
     private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
-            String appDataDir, boolean isTopApp, String[] pkgDataInfoList);
+            String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
+            boolean bindMountAppStorageDirs);
 
     /**
      * Specialize an unspecialized app process.  The current VM must have been started
@@ -339,14 +371,15 @@
      * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
      * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
      * app_b_ce_inode, ...];
+     * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
      */
     private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName,
             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
-            String[] pkgDataInfoList) {
+            String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
         nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
                 niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
-                pkgDataInfoList);
+                pkgDataInfoList, bindMountAppStorageDirs);
 
         // Note that this event ends at the end of handleChildProc.
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -366,7 +399,7 @@
     private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
-            String[] pkgDataInfoList);
+            String[] pkgDataInfoList, boolean bindMountAppStorageDirs);
 
     /**
      * Called to do any initialization before starting an application.
@@ -691,7 +724,7 @@
                                  args.mRuntimeFlags, rlimits, args.mMountExternal,
                                  args.mSeInfo, args.mNiceName, args.mStartChildZygote,
                                  args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
-                                 args.mPkgDataInfoList);
+                                 args.mPkgDataInfoList, args.mBindMountAppStorageDirs);
 
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 37f570b..1a63765 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -227,6 +227,11 @@
     String[] mPkgDataInfoList;
 
     /**
+     * @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
+     */
+    boolean mBindMountAppStorageDirs;
+
+    /**
      * Constructs instance and parses args
      *
      * @param args zygote command-line args
@@ -447,6 +452,8 @@
                 }
             } else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
                 mPkgDataInfoList = getAssignmentList(arg);
+            } else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
+                mBindMountAppStorageDirs = true;
             } else {
                 break;
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4949811..bc8dfd4 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -258,7 +258,7 @@
                 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
-                parsedArgs.mPkgDataInfoList);
+                parsedArgs.mPkgDataInfoList, parsedArgs.mBindMountAppStorageDirs);
 
         try {
             if (pid == 0) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 54cf693..ec1f516 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -125,12 +125,6 @@
 
     private static boolean sPreloadComplete;
 
-    /**
-     * Cached classloader to use for the system server. Will only be populated in the system
-     * server process.
-     */
-    private static ClassLoader sCachedSystemServerClassLoader = null;
-
     static void preload(TimingsTraceLog bootTimingsTraceLog) {
         Log.d(TAG, "begin preload");
         bootTimingsTraceLog.traceBegin("BeginPreload");
@@ -508,13 +502,7 @@
 
         final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
         if (systemServerClasspath != null) {
-            if (performSystemServerDexOpt(systemServerClasspath)) {
-                // Throw away the cached classloader. If we compiled here, the classloader would
-                // not have had AoT-ed artifacts.
-                // Note: This only works in a very special environment where selinux enforcement is
-                // disabled, e.g., Mac builds.
-                sCachedSystemServerClassLoader = null;
-            }
+            performSystemServerDexOpt(systemServerClasspath);
             // Capturing profiles is only supported for debug or eng builds since selinux normally
             // prevents it.
             if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
@@ -546,9 +534,10 @@
 
             throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
         } else {
-            createSystemServerClassLoader();
-            ClassLoader cl = sCachedSystemServerClassLoader;
-            if (cl != null) {
+            ClassLoader cl = null;
+            if (systemServerClasspath != null) {
+                cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
+
                 Thread.currentThread().setContextClassLoader(cl);
             }
 
@@ -564,24 +553,6 @@
     }
 
     /**
-     * Create the classloader for the system server and store it in
-     * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in
-     * system server startup, when the runtime is in a critically low state. Do not do
-     * extended computation etc here.
-     */
-    private static void createSystemServerClassLoader() {
-        if (sCachedSystemServerClassLoader != null) {
-            return;
-        }
-        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
-        // TODO: Should we run optimization here?
-        if (systemServerClasspath != null) {
-            sCachedSystemServerClassLoader = createPathClassLoader(systemServerClasspath,
-                    VMRuntime.SDK_VERSION_CUR_DEVELOPMENT);
-        }
-    }
-
-    /**
      * Note that preparing the profiles for system server does not require special selinux
      * permissions. From the installer perspective the system server is a regular package which can
      * capture profile information.
@@ -645,16 +616,15 @@
 
     /**
      * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
-     * set of the current runtime. If something was compiled, return true.
+     * set of the current runtime.
      */
-    private static boolean performSystemServerDexOpt(String classPath) {
+    private static void performSystemServerDexOpt(String classPath) {
         final String[] classPathElements = classPath.split(":");
         final IInstalld installd = IInstalld.Stub
                 .asInterface(ServiceManager.getService("installd"));
         final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
 
         String classPathForElement = "";
-        boolean compiledSomething = false;
         for (String classPathElement : classPathElements) {
             // We default to the verify filter because the compilation will happen on /data and
             // system server cannot load executable code outside /system.
@@ -695,7 +665,6 @@
                             uuid, classLoaderContext, seInfo, false /* downgrade */,
                             targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
                             "server-dexopt");
-                    compiledSomething = true;
                 } catch (RemoteException | ServiceSpecificException e) {
                     // Ignore (but log), we need this on the classpath for fallback mode.
                     Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -706,8 +675,6 @@
             classPathForElement = encodeSystemServerClassPath(
                     classPathForElement, classPathElement);
         }
-
-        return compiledSomething;
     }
 
     /**
@@ -794,6 +761,10 @@
              * this is present in all ARMv8 CPUs; this flag has no effect on other platforms. */
             parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
 
+            /* Enable gwp-asan on the system server with a small probability. This is the same
+             * policy as applied to native processes and system apps. */
+            parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;
+
             if (shouldProfileSystemServer()) {
                 parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
             }
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
new file mode 100644
index 0000000..ebfea450
--- /dev/null
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -0,0 +1,78 @@
+/*
+ * 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.internal.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+/**
+ * @hide
+ */
+public class GestureNavigationSettingsObserver extends ContentObserver {
+    private Context mContext;
+    private Runnable mOnChangeRunnable;
+
+    public GestureNavigationSettingsObserver(Handler handler, Context context,
+            Runnable onChangeRunnable) {
+        super(handler);
+        mContext = context;
+        mOnChangeRunnable = onChangeRunnable;
+    }
+
+    public void register() {
+        ContentResolver r = mContext.getContentResolver();
+        r.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
+                false, this, UserHandle.USER_ALL);
+        r.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
+                false, this, UserHandle.USER_ALL);
+    }
+
+    public void unregister() {
+        mContext.getContentResolver().unregisterContentObserver(this);
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        super.onChange(selfChange);
+        if (mOnChangeRunnable != null) {
+            mOnChangeRunnable.run();
+        }
+    }
+
+    public int getLeftSensitivity(Resources userRes) {
+        return getSensitivity(userRes, Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT);
+    }
+
+    public int getRightSensitivity(Resources userRes) {
+        return getSensitivity(userRes, Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT);
+    }
+
+    private int getSensitivity(Resources userRes, String side) {
+        final int inset = userRes.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_backGestureInset);
+        final float scale = Settings.Secure.getFloatForUser(
+                mContext.getContentResolver(), side, 1.0f, UserHandle.USER_CURRENT);
+        return (int) (inset * scale);
+    }
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 380a20c..5b79b18 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -136,7 +136,8 @@
 
     // Used to show the authentication dialog (Biometrics, Device Credential)
     void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int biometricModality, boolean requireConfirmation, int userId, String opPackageName);
+            int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
+            long operationId);
     // Used to notify the authentication dialog that a biometric has been authenticated
     void onBiometricAuthenticated();
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 9907b99..1dbd69c 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -105,7 +105,8 @@
 
     // Used to show the authentication dialog (Biometrics, Device Credential)
     void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int biometricModality, boolean requireConfirmation, int userId, String opPackageName);
+            int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
+            long operationId);
     // Used to notify the authentication dialog that a biometric has been authenticated
     void onBiometricAuthenticated();
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 9b2bcfb..488b18d 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.util;
 
+import static java.util.Collections.emptySet;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.ArrayMap;
@@ -67,7 +69,7 @@
      */
     public static @NonNull <T> Set<T> filter(@Nullable Set<T> set,
             java.util.function.Predicate<? super T> predicate) {
-        if (set == null || set.size() == 0) return Collections.emptySet();
+        if (set == null || set.size() == 0) return emptySet();
         ArraySet<T> result = null;
         if (set instanceof ArraySet) {
             ArraySet<T> arraySet = (ArraySet<T>) set;
@@ -123,7 +125,7 @@
      */
     public static @NonNull <I, O> Set<O> map(@Nullable Set<I> cur,
             Function<? super I, ? extends O> f) {
-        if (isEmpty(cur)) return Collections.emptySet();
+        if (isEmpty(cur)) return emptySet();
         ArraySet<O> result = new ArraySet<>();
         if (cur instanceof ArraySet) {
             ArraySet<I> arraySet = (ArraySet<I>) cur;
@@ -182,7 +184,7 @@
      * @see Collections#emptySet
      */
     public static @NonNull <T> Set<T> emptyIfNull(@Nullable Set<T> cur) {
-        return cur == null ? Collections.emptySet() : cur;
+        return cur == null ? emptySet() : cur;
     }
 
     /**
@@ -325,9 +327,9 @@
      */
     public static @NonNull <T> Set<T> addAll(@Nullable Set<T> cur, @Nullable Collection<T> val) {
         if (isEmpty(val)) {
-            return cur != null ? cur : Collections.emptySet();
+            return cur != null ? cur : emptySet();
         }
-        if (cur == null || cur == Collections.emptySet()) {
+        if (cur == null || cur == emptySet()) {
             cur = new ArraySet<>();
         }
         cur.addAll(val);
@@ -338,7 +340,7 @@
      * @see #add(List, Object)
      */
     public static @NonNull <T> Set<T> add(@Nullable Set<T> cur, T val) {
-        if (cur == null || cur == Collections.emptySet()) {
+        if (cur == null || cur == emptySet()) {
             cur = new ArraySet<>();
         }
         cur.add(val);
@@ -390,7 +392,14 @@
      * @return a list that will not be affected by mutations to the given original list.
      */
     public static @NonNull <T> Set<T> copyOf(@Nullable Set<T> cur) {
-        return isEmpty(cur) ? Collections.emptySet() : new ArraySet<>(cur);
+        return isEmpty(cur) ? emptySet() : new ArraySet<>(cur);
+    }
+
+    /**
+     * @return a {@link Set} representing the given collection.
+     */
+    public static @NonNull <T> Set<T> toSet(@Nullable Collection<T> cur) {
+        return isEmpty(cur) ? emptySet() : new ArraySet<>(cur);
     }
 
     /**
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 7f567b9..dd64c40 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -221,6 +221,33 @@
             }
         }
 
+        class ForInternedStringArraySet implements Parcelling<ArraySet<String>> {
+            @Override
+            public void parcel(ArraySet<String> item, Parcel dest, int parcelFlags) {
+                if (item == null) {
+                    dest.writeInt(-1);
+                } else {
+                    dest.writeInt(item.size());
+                    for (String string : item) {
+                        dest.writeString(string);
+                    }
+                }
+            }
+
+            @Override
+            public ArraySet<String> unparcel(Parcel source) {
+                final int size = source.readInt();
+                if (size < 0) {
+                  return null;
+                }
+                ArraySet<String> set = new ArraySet<>();
+                for (int count = 0; count < size; count++) {
+                    set.add(TextUtils.safeIntern(source.readString()));
+                }
+                return set;
+            }
+        }
+
         class ForBoolean implements Parcelling<Boolean> {
             @Override
             public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) {
diff --git a/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl b/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl
index 29bdf56..feb3f02 100644
--- a/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl
+++ b/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl
@@ -24,4 +24,6 @@
  */
 oneway interface IInlineContentCallback {
     void onContent(in SurfaceControlViewHost.SurfacePackage content);
+    void onClick();
+    void onLongClick();
 }
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 74ad815..bd0623e 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -32,6 +32,7 @@
 import android.widget.RemoteViews;
 
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * An ImageView for displaying an Icon. Avoids reloading the Icon when possible.
@@ -44,6 +45,7 @@
     private boolean mInternalSetDrawable;
     private boolean mForceHidden;
     private int mDesiredVisibility;
+    private Consumer<Integer> mOnVisibilityChangedListener;
 
     @UnsupportedAppUsage
     public CachingIconView(Context context, @Nullable AttributeSet attrs) {
@@ -198,6 +200,13 @@
     private void updateVisibility() {
         int visibility = mDesiredVisibility == VISIBLE && mForceHidden ? INVISIBLE
                 : mDesiredVisibility;
+        if (mOnVisibilityChangedListener != null) {
+            mOnVisibilityChangedListener.accept(visibility);
+        }
         super.setVisibility(visibility);
     }
+
+    public void setOnVisibilityChangedListener(Consumer<Integer> listener) {
+        mOnVisibilityChangedListener = listener;
+    }
 }
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
new file mode 100644
index 0000000..73da600
--- /dev/null
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -0,0 +1,909 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.app.Person;
+import android.app.RemoteInputHistoryItem;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.graphics.ColorUtils;
+import com.android.internal.util.ContrastColorUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.regex.Pattern;
+
+/**
+ * A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
+ * messages and adapts the layout accordingly.
+ */
+@RemoteViews.RemoteView
+public class ConversationLayout extends FrameLayout
+        implements ImageMessageConsumer, IMessagingLayout {
+
+    public static final boolean CONVERSATION_LAYOUT_ENABLED = true;
+    private static final float COLOR_SHIFT_AMOUNT = 60;
+    /**
+     *  Pattren for filter some ingonable characters.
+     *  p{Z} for any kind of whitespace or invisible separator.
+     *  p{C} for any kind of punctuation character.
+     */
+    private static final Pattern IGNORABLE_CHAR_PATTERN
+            = Pattern.compile("[\\p{C}\\p{Z}]");
+    private static final Pattern SPECIAL_CHAR_PATTERN
+            = Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]");
+    private static final Consumer<MessagingMessage> REMOVE_MESSAGE
+            = MessagingMessage::removeMessage;
+    public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+    public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+    public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+    public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
+            = new MessagingPropertyAnimator();
+    private List<MessagingMessage> mMessages = new ArrayList<>();
+    private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
+    private MessagingLinearLayout mMessagingLinearLayout;
+    private boolean mShowHistoricMessages;
+    private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
+    private TextView mTitleView;
+    private int mLayoutColor;
+    private int mSenderTextColor;
+    private int mMessageTextColor;
+    private int mAvatarSize;
+    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private Paint mTextPaint = new Paint();
+    private Icon mAvatarReplacement;
+    private boolean mIsOneToOne;
+    private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
+    private Person mUser;
+    private CharSequence mNameReplacement;
+    private boolean mIsCollapsed;
+    private ImageResolver mImageResolver;
+    private ImageView mConversationIcon;
+    private TextView mConversationText;
+    private View mConversationIconBadge;
+    private Icon mLargeIcon;
+    private View mExpandButtonContainer;
+    private ViewGroup mExpandButtonAndContentContainer;
+    private NotificationExpandButton mExpandButton;
+    private int mExpandButtonExpandedTopMargin;
+    private int mBadgedSideMargins;
+    private int mIconSizeBadged;
+    private int mIconSizeCentered;
+    private CachingIconView mIcon;
+    private int mExpandedGroupTopMargin;
+    private int mExpandButtonExpandedSize;
+    private View mConversationFacePile;
+    private int mNotificationBackgroundColor;
+    private CharSequence mFallbackChatName;
+    private CharSequence mFallbackGroupChatName;
+    private CharSequence mConversationTitle;
+    private int mNotificationHeaderExpandedPadding;
+    private View mConversationHeader;
+    private View mContentContainer;
+    private boolean mExpandable = true;
+    private int mContentMarginEnd;
+
+    public ConversationLayout(@NonNull Context context) {
+        super(context);
+    }
+
+    public ConversationLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ConversationLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public ConversationLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mMessagingLinearLayout = findViewById(R.id.notification_messaging);
+        mMessagingLinearLayout.setMessagingLayout(this);
+        // We still want to clip, but only on the top, since views can temporarily out of bounds
+        // during transitions.
+        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+        int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
+        Rect rect = new Rect(0, 0, size, size);
+        mMessagingLinearLayout.setClipBounds(rect);
+        mTitleView = findViewById(R.id.title);
+        mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+        mTextPaint.setAntiAlias(true);
+        mConversationIcon = findViewById(R.id.conversation_icon);
+        mIcon = findViewById(R.id.icon);
+        mConversationIconBadge = findViewById(R.id.conversation_icon_badge);
+        mIcon.setOnVisibilityChangedListener((visibility) -> {
+            // Always keep the badge visibility in sync with the icon. This is necessary in cases
+            // Where the icon is being hidden externally like in group children.
+            mConversationIconBadge.setVisibility(visibility);
+        });
+        mConversationText = findViewById(R.id.conversation_text);
+        mExpandButtonContainer = findViewById(R.id.expand_button_container);
+        mConversationHeader = findViewById(R.id.conversation_header);
+        mContentContainer = findViewById(R.id.notification_action_list_margin_target);
+        mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
+        mExpandButton = findViewById(R.id.expand_button);
+        mExpandButtonExpandedTopMargin = getResources().getDimensionPixelSize(
+                R.dimen.conversation_expand_button_top_margin_expanded);
+        mExpandButtonExpandedSize = getResources().getDimensionPixelSize(
+                R.dimen.conversation_expand_button_expanded_size);
+        mNotificationHeaderExpandedPadding = getResources().getDimensionPixelSize(
+                R.dimen.conversation_header_expanded_padding_end);
+        mContentMarginEnd = getResources().getDimensionPixelSize(
+                R.dimen.notification_content_margin_end);
+        mBadgedSideMargins = getResources().getDimensionPixelSize(
+                R.dimen.conversation_badge_side_margin);
+        mIconSizeBadged = getResources().getDimensionPixelSize(
+                R.dimen.conversation_icon_size_badged);
+        mIconSizeCentered = getResources().getDimensionPixelSize(
+                R.dimen.conversation_icon_size_centered);
+        mExpandedGroupTopMargin = getResources().getDimensionPixelSize(
+                R.dimen.conversation_icon_margin_top_centered);
+        mConversationFacePile = findViewById(R.id.conversation_face_pile);
+        mFallbackChatName = getResources().getString(
+                R.string.conversation_title_fallback_one_to_one);
+        mFallbackGroupChatName = getResources().getString(
+                R.string.conversation_title_fallback_group_chat);
+    }
+
+    @RemotableViewMethod
+    public void setAvatarReplacement(Icon icon) {
+        mAvatarReplacement = icon;
+    }
+
+    @RemotableViewMethod
+    public void setNameReplacement(CharSequence nameReplacement) {
+        mNameReplacement = nameReplacement;
+    }
+
+    /**
+     * Set this layout to show the collapsed representation.
+     *
+     * @param isCollapsed is it collapsed
+     */
+    @RemotableViewMethod
+    public void setIsCollapsed(boolean isCollapsed) {
+        mIsCollapsed = isCollapsed;
+        mMessagingLinearLayout.setMaxDisplayedLines(isCollapsed ? 1 : Integer.MAX_VALUE);
+        updateExpandButton();
+        updateContentPaddings();
+    }
+
+    @RemotableViewMethod
+    public void setData(Bundle extras) {
+        Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+        List<Notification.MessagingStyle.Message> newMessages
+                = Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+        Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
+        List<Notification.MessagingStyle.Message> newHistoricMessages
+                = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+
+        // mUser now set (would be nice to avoid the side effect but WHATEVER)
+        setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
+
+
+        // Append remote input history to newMessages (again, side effect is lame but WHATEVS)
+        RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
+                extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+        addRemoteInputHistoryToMessages(newMessages, history);
+
+        boolean showSpinner =
+                extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
+
+        // bind it, baby
+        bind(newMessages, newHistoricMessages, showSpinner);
+    }
+
+    @Override
+    public void setImageResolver(ImageResolver resolver) {
+        mImageResolver = resolver;
+    }
+
+    private void addRemoteInputHistoryToMessages(
+            List<Notification.MessagingStyle.Message> newMessages,
+            RemoteInputHistoryItem[] remoteInputHistory) {
+        if (remoteInputHistory == null || remoteInputHistory.length == 0) {
+            return;
+        }
+        for (int i = remoteInputHistory.length - 1; i >= 0; i--) {
+            RemoteInputHistoryItem historyMessage = remoteInputHistory[i];
+            Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message(
+                    historyMessage.getText(), 0, (Person) null, true /* remoteHistory */);
+            if (historyMessage.getUri() != null) {
+                message.setData(historyMessage.getMimeType(), historyMessage.getUri());
+            }
+            newMessages.add(message);
+        }
+    }
+
+    private void bind(List<Notification.MessagingStyle.Message> newMessages,
+            List<Notification.MessagingStyle.Message> newHistoricMessages,
+            boolean showSpinner) {
+        // convert MessagingStyle.Message to MessagingMessage, re-using ones from a previous binding
+        // if they exist
+        List<MessagingMessage> historicMessages = createMessages(newHistoricMessages,
+                true /* isHistoric */);
+        List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */);
+
+        // Copy our groups, before they get clobbered
+        ArrayList<MessagingGroup> oldGroups = new ArrayList<>(mGroups);
+
+        // Add our new MessagingMessages to groups
+        List<List<MessagingMessage>> groups = new ArrayList<>();
+        List<Person> senders = new ArrayList<>();
+
+        // Lets first find the groups (populate `groups` and `senders`)
+        findGroups(historicMessages, messages, groups, senders);
+
+        // Let's now create the views and reorder them accordingly
+        //   side-effect: updates mGroups, mAddedGroups
+        createGroupViews(groups, senders, showSpinner);
+
+        // Let's first check which groups were removed altogether and remove them in one animation
+        removeGroups(oldGroups);
+
+        // Let's remove the remaining messages
+        mMessages.forEach(REMOVE_MESSAGE);
+        mHistoricMessages.forEach(REMOVE_MESSAGE);
+
+        mMessages = messages;
+        mHistoricMessages = historicMessages;
+
+        updateHistoricMessageVisibility();
+        updateTitleAndNamesDisplay();
+
+        updateConversationLayout();
+
+    }
+
+    /**
+     * Update the layout according to the data provided (i.e mIsOneToOne, expanded etc);
+     */
+    private void updateConversationLayout() {
+        // TODO: resolve this from shortcuts
+        // Set avatar and name
+        CharSequence conversationText = mConversationTitle;
+        // TODO: display the secondary text somewhere
+        if (mIsOneToOne) {
+            // Let's resolve the icon / text from the last sender
+            mConversationIcon.setVisibility(VISIBLE);
+            mConversationFacePile.setVisibility(GONE);
+            CharSequence userKey = getKey(mUser);
+            for (int i = mGroups.size() - 1; i >= 0; i--) {
+                MessagingGroup messagingGroup = mGroups.get(i);
+                Person messageSender = messagingGroup.getSender();
+                if ((messageSender != null && !TextUtils.equals(userKey, getKey(messageSender)))
+                        || i == 0) {
+                    if (TextUtils.isEmpty(conversationText)) {
+                        // We use the sendername as header text if no conversation title is provided
+                        // (This usually happens for most 1:1 conversations)
+                        conversationText = messagingGroup.getSenderName();
+                    }
+                    Icon avatarIcon = messagingGroup.getAvatarIcon();
+                    if (avatarIcon == null) {
+                        avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor);
+                    }
+                    mConversationIcon.setImageIcon(avatarIcon);
+                    break;
+                }
+            }
+        } else {
+            if (mIsCollapsed) {
+                if (mLargeIcon != null) {
+                    mConversationIcon.setVisibility(VISIBLE);
+                    mConversationFacePile.setVisibility(GONE);
+                    mConversationIcon.setImageIcon(mLargeIcon);
+                } else {
+                    mConversationIcon.setVisibility(GONE);
+                    // This will also inflate it!
+                    mConversationFacePile.setVisibility(VISIBLE);
+                    mConversationFacePile = findViewById(R.id.conversation_face_pile);
+                    bindFacePile();
+                }
+            } else {
+                mConversationFacePile.setVisibility(GONE);
+                mConversationIcon.setVisibility(GONE);
+            }
+        }
+        if (TextUtils.isEmpty(conversationText)) {
+            conversationText = mIsOneToOne ? mFallbackChatName : mFallbackGroupChatName;
+        }
+        mConversationText.setText(conversationText);
+        // Update if the groups can hide the sender if they are first (applies to 1:1 conversations)
+        // This needs to happen after all of the above o update all of the groups
+        for (int i = mGroups.size() - 1; i >= 0; i--) {
+            MessagingGroup messagingGroup = mGroups.get(i);
+            CharSequence messageSender = messagingGroup.getSenderName();
+            boolean canHide = mIsOneToOne
+                    && TextUtils.equals(conversationText, messageSender);
+            messagingGroup.setCanHideSenderIfFirst(canHide);
+        }
+        updateIconPositionAndSize();
+    }
+
+    private void bindFacePile() {
+        // Let's bind the face pile
+        View bottomBackground = mConversationFacePile.findViewById(
+                R.id.conversation_face_pile_bottom_background);
+        applyNotificationBackgroundColor(bottomBackground);
+        ImageView bottomView = mConversationFacePile.findViewById(
+                R.id.conversation_face_pile_bottom);
+        ImageView topView = mConversationFacePile.findViewById(
+                R.id.conversation_face_pile_top);
+        // Let's find the two last conversations:
+        Icon secondLastIcon = null;
+        CharSequence lastKey = null;
+        Icon lastIcon = null;
+        CharSequence userKey = getKey(mUser);
+        for (int i = mGroups.size() - 1; i >= 0; i--) {
+            MessagingGroup messagingGroup = mGroups.get(i);
+            Person messageSender = messagingGroup.getSender();
+            boolean notUser = messageSender != null
+                    && !TextUtils.equals(userKey, getKey(messageSender));
+            boolean notIncluded = messageSender != null
+                    && !TextUtils.equals(lastKey, getKey(messageSender));
+            if ((notUser && notIncluded)
+                    || (i == 0 && lastKey == null)) {
+                if (lastIcon == null) {
+                    lastIcon = messagingGroup.getAvatarIcon();
+                    lastKey = getKey(messageSender);
+                } else {
+                    secondLastIcon = messagingGroup.getAvatarIcon();
+                    break;
+                }
+            }
+        }
+        if (lastIcon == null) {
+            lastIcon = createAvatarSymbol(" ", "", mLayoutColor);
+        }
+        bottomView.setImageIcon(lastIcon);
+        if (secondLastIcon == null) {
+            secondLastIcon = createAvatarSymbol("", "", mLayoutColor);
+        }
+        topView.setImageIcon(secondLastIcon);
+    }
+
+    /**
+     * update the icon position and sizing
+     */
+    private void updateIconPositionAndSize() {
+        int gravity;
+        int marginStart;
+        int marginTop;
+        int iconSize;
+        if (mIsOneToOne || mIsCollapsed) {
+            // Baded format
+            gravity = Gravity.LEFT;
+            marginStart = mBadgedSideMargins;
+            marginTop = mBadgedSideMargins;
+            iconSize = mIconSizeBadged;
+        } else {
+            gravity = Gravity.CENTER_HORIZONTAL;
+            marginStart = 0;
+            marginTop = mExpandedGroupTopMargin;
+            iconSize = mIconSizeCentered;
+        }
+        LayoutParams layoutParams =
+                (LayoutParams) mConversationIconBadge.getLayoutParams();
+        layoutParams.gravity = gravity;
+        layoutParams.topMargin = marginTop;
+        layoutParams.setMarginStart(marginStart);
+        mConversationIconBadge.setLayoutParams(layoutParams);
+        ViewGroup.LayoutParams iconParams = mIcon.getLayoutParams();
+        iconParams.width = iconSize;
+        iconParams.height = iconSize;
+        mIcon.setLayoutParams(iconParams);
+    }
+
+    @RemotableViewMethod
+    public void setLargeIcon(Icon largeIcon) {
+        mLargeIcon = largeIcon;
+    }
+
+    /**
+     * Sets the conversation title of this conversation.
+     *
+     * @param conversationTitle the conversation title
+     */
+    @RemotableViewMethod
+    public void setConversationTitle(CharSequence conversationTitle) {
+        mConversationTitle = conversationTitle;
+    }
+
+    private void removeGroups(ArrayList<MessagingGroup> oldGroups) {
+        int size = oldGroups.size();
+        for (int i = 0; i < size; i++) {
+            MessagingGroup group = oldGroups.get(i);
+            if (!mGroups.contains(group)) {
+                List<MessagingMessage> messages = group.getMessages();
+                Runnable endRunnable = () -> {
+                    mMessagingLinearLayout.removeTransientView(group);
+                    group.recycle();
+                };
+
+                boolean wasShown = group.isShown();
+                mMessagingLinearLayout.removeView(group);
+                if (wasShown && !MessagingLinearLayout.isGone(group)) {
+                    mMessagingLinearLayout.addTransientView(group, 0);
+                    group.removeGroupAnimated(endRunnable);
+                } else {
+                    endRunnable.run();
+                }
+                mMessages.removeAll(messages);
+                mHistoricMessages.removeAll(messages);
+            }
+        }
+    }
+
+    private void updateTitleAndNamesDisplay() {
+        ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
+        ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
+        for (int i = 0; i < mGroups.size(); i++) {
+            MessagingGroup group = mGroups.get(i);
+            CharSequence senderName = group.getSenderName();
+            if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
+                continue;
+            }
+            if (!uniqueNames.containsKey(senderName)) {
+                // Only use visible characters to get uniqueNames
+                String pureSenderName = IGNORABLE_CHAR_PATTERN
+                        .matcher(senderName).replaceAll("" /* replacement */);
+                char c = pureSenderName.charAt(0);
+                if (uniqueCharacters.containsKey(c)) {
+                    // this character was already used, lets make it more unique. We first need to
+                    // resolve the existing character if it exists
+                    CharSequence existingName = uniqueCharacters.get(c);
+                    if (existingName != null) {
+                        uniqueNames.put(existingName, findNameSplit((String) existingName));
+                        uniqueCharacters.put(c, null);
+                    }
+                    uniqueNames.put(senderName, findNameSplit((String) senderName));
+                } else {
+                    uniqueNames.put(senderName, Character.toString(c));
+                    uniqueCharacters.put(c, pureSenderName);
+                }
+            }
+        }
+
+        // Now that we have the correct symbols, let's look what we have cached
+        ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
+        for (int i = 0; i < mGroups.size(); i++) {
+            // Let's now set the avatars
+            MessagingGroup group = mGroups.get(i);
+            boolean isOwnMessage = group.getSender() == mUser;
+            CharSequence senderName = group.getSenderName();
+            if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)
+                    || (mIsOneToOne && mAvatarReplacement != null && !isOwnMessage)) {
+                continue;
+            }
+            String symbol = uniqueNames.get(senderName);
+            Icon cachedIcon = group.getAvatarSymbolIfMatching(senderName,
+                    symbol, mLayoutColor);
+            if (cachedIcon != null) {
+                cachedAvatars.put(senderName, cachedIcon);
+            }
+        }
+
+        for (int i = 0; i < mGroups.size(); i++) {
+            // Let's now set the avatars
+            MessagingGroup group = mGroups.get(i);
+            CharSequence senderName = group.getSenderName();
+            if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
+                continue;
+            }
+            if (mIsOneToOne && mAvatarReplacement != null && group.getSender() != mUser) {
+                group.setAvatar(mAvatarReplacement);
+            } else {
+                Icon cachedIcon = cachedAvatars.get(senderName);
+                if (cachedIcon == null) {
+                    cachedIcon = createAvatarSymbol(senderName, uniqueNames.get(senderName),
+                            mLayoutColor);
+                    cachedAvatars.put(senderName, cachedIcon);
+                }
+                group.setCreatedAvatar(cachedIcon, senderName, uniqueNames.get(senderName),
+                        mLayoutColor);
+            }
+        }
+    }
+
+    private Icon createAvatarSymbol(CharSequence senderName, String symbol, int layoutColor) {
+        if (symbol.isEmpty() || TextUtils.isDigitsOnly(symbol) ||
+                SPECIAL_CHAR_PATTERN.matcher(symbol).find()) {
+            Icon avatarIcon = Icon.createWithResource(getContext(),
+                    R.drawable.messaging_user);
+            avatarIcon.setTint(findColor(senderName, layoutColor));
+            return avatarIcon;
+        } else {
+            Bitmap bitmap = Bitmap.createBitmap(mAvatarSize, mAvatarSize, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+            float radius = mAvatarSize / 2.0f;
+            int color = findColor(senderName, layoutColor);
+            mPaint.setColor(color);
+            canvas.drawCircle(radius, radius, radius, mPaint);
+            boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f;
+            mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
+            mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.5f : mAvatarSize * 0.3f);
+            int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
+            canvas.drawText(symbol, radius, yPos, mTextPaint);
+            return Icon.createWithBitmap(bitmap);
+        }
+    }
+
+    private int findColor(CharSequence senderName, int layoutColor) {
+        double luminance = ContrastColorUtil.calculateLuminance(layoutColor);
+        float shift = Math.abs(senderName.hashCode()) % 5 / 4.0f - 0.5f;
+
+        // we need to offset the range if the luminance is too close to the borders
+        shift += Math.max(COLOR_SHIFT_AMOUNT / 2.0f / 100 - luminance, 0);
+        shift -= Math.max(COLOR_SHIFT_AMOUNT / 2.0f / 100 - (1.0f - luminance), 0);
+        return ContrastColorUtil.getShiftedColor(layoutColor,
+                (int) (shift * COLOR_SHIFT_AMOUNT));
+    }
+
+    private String findNameSplit(String existingName) {
+        String[] split = existingName.split(" ");
+        if (split.length > 1) {
+            return Character.toString(split[0].charAt(0))
+                    + Character.toString(split[1].charAt(0));
+        }
+        return existingName.substring(0, 1);
+    }
+
+    @RemotableViewMethod
+    public void setLayoutColor(int color) {
+        mLayoutColor = color;
+    }
+
+    @RemotableViewMethod
+    public void setIsOneToOne(boolean oneToOne) {
+        mIsOneToOne = oneToOne;
+    }
+
+    @RemotableViewMethod
+    public void setSenderTextColor(int color) {
+        mSenderTextColor = color;
+    }
+
+    /**
+     * @param color the color of the notification background
+     */
+    @RemotableViewMethod
+    public void setNotificationBackgroundColor(int color) {
+        mNotificationBackgroundColor = color;
+        applyNotificationBackgroundColor(mConversationIconBadge);
+    }
+
+    private void applyNotificationBackgroundColor(View view) {
+        view.setBackgroundTintList(ColorStateList.valueOf(mNotificationBackgroundColor));
+    }
+
+    @RemotableViewMethod
+    public void setMessageTextColor(int color) {
+        mMessageTextColor = color;
+    }
+
+    private void setUser(Person user) {
+        mUser = user;
+        if (mUser.getIcon() == null) {
+            Icon userIcon = Icon.createWithResource(getContext(),
+                    R.drawable.messaging_user);
+            userIcon.setTint(mLayoutColor);
+            mUser = mUser.toBuilder().setIcon(userIcon).build();
+        }
+    }
+
+    private void createGroupViews(List<List<MessagingMessage>> groups,
+            List<Person> senders, boolean showSpinner) {
+        mGroups.clear();
+        for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) {
+            List<MessagingMessage> group = groups.get(groupIndex);
+            MessagingGroup newGroup = null;
+            // we'll just take the first group that exists or create one there is none
+            for (int messageIndex = group.size() - 1; messageIndex >= 0; messageIndex--) {
+                MessagingMessage message = group.get(messageIndex);
+                newGroup = message.getGroup();
+                if (newGroup != null) {
+                    break;
+                }
+            }
+            // Create a new group, adding it to the linear layout as well
+            if (newGroup == null) {
+                newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
+                mAddedGroups.add(newGroup);
+            }
+            newGroup.setDisplayImagesAtEnd(mIsCollapsed);
+            newGroup.setIsInConversation(true);
+            newGroup.setLayoutColor(mLayoutColor);
+            newGroup.setTextColors(mSenderTextColor, mMessageTextColor);
+            Person sender = senders.get(groupIndex);
+            CharSequence nameOverride = null;
+            if (sender != mUser && mNameReplacement != null) {
+                nameOverride = mNameReplacement;
+            }
+            newGroup.setShowingAvatar(!mIsOneToOne && !mIsCollapsed);
+            newGroup.setSingleLine(mIsCollapsed);
+            newGroup.setSender(sender, nameOverride);
+            newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
+            mGroups.add(newGroup);
+
+            // Reposition to the correct place (if we're re-using a group)
+            if (mMessagingLinearLayout.indexOfChild(newGroup) != groupIndex) {
+                mMessagingLinearLayout.removeView(newGroup);
+                mMessagingLinearLayout.addView(newGroup, groupIndex);
+            }
+            newGroup.setMessages(group);
+        }
+    }
+
+    private void findGroups(List<MessagingMessage> historicMessages,
+            List<MessagingMessage> messages, List<List<MessagingMessage>> groups,
+            List<Person> senders) {
+        CharSequence currentSenderKey = null;
+        List<MessagingMessage> currentGroup = null;
+        int histSize = historicMessages.size();
+        for (int i = 0; i < histSize + messages.size(); i++) {
+            MessagingMessage message;
+            if (i < histSize) {
+                message = historicMessages.get(i);
+            } else {
+                message = messages.get(i - histSize);
+            }
+            boolean isNewGroup = currentGroup == null;
+            Person sender = message.getMessage().getSenderPerson();
+            CharSequence key = getKey(sender);
+            isNewGroup |= !TextUtils.equals(key, currentSenderKey);
+            if (isNewGroup) {
+                currentGroup = new ArrayList<>();
+                groups.add(currentGroup);
+                if (sender == null) {
+                    sender = mUser;
+                }
+                senders.add(sender);
+                currentSenderKey = key;
+            }
+            currentGroup.add(message);
+        }
+    }
+
+    private CharSequence getKey(Person person) {
+        return person == null ? null : person.getKey() == null ? person.getName() : person.getKey();
+    }
+
+    /**
+     * Creates new messages, reusing existing ones if they are available.
+     *
+     * @param newMessages the messages to parse.
+     */
+    private List<MessagingMessage> createMessages(
+            List<Notification.MessagingStyle.Message> newMessages, boolean historic) {
+        List<MessagingMessage> result = new ArrayList<>();
+        for (int i = 0; i < newMessages.size(); i++) {
+            Notification.MessagingStyle.Message m = newMessages.get(i);
+            MessagingMessage message = findAndRemoveMatchingMessage(m);
+            if (message == null) {
+                message = MessagingMessage.createMessage(this, m, mImageResolver);
+            }
+            message.setIsHistoric(historic);
+            result.add(message);
+        }
+        return result;
+    }
+
+    private MessagingMessage findAndRemoveMatchingMessage(Notification.MessagingStyle.Message m) {
+        for (int i = 0; i < mMessages.size(); i++) {
+            MessagingMessage existing = mMessages.get(i);
+            if (existing.sameAs(m)) {
+                mMessages.remove(i);
+                return existing;
+            }
+        }
+        for (int i = 0; i < mHistoricMessages.size(); i++) {
+            MessagingMessage existing = mHistoricMessages.get(i);
+            if (existing.sameAs(m)) {
+                mHistoricMessages.remove(i);
+                return existing;
+            }
+        }
+        return null;
+    }
+
+    public void showHistoricMessages(boolean show) {
+        mShowHistoricMessages = show;
+        updateHistoricMessageVisibility();
+    }
+
+    private void updateHistoricMessageVisibility() {
+        int numHistoric = mHistoricMessages.size();
+        for (int i = 0; i < numHistoric; i++) {
+            MessagingMessage existing = mHistoricMessages.get(i);
+            existing.setVisibility(mShowHistoricMessages ? VISIBLE : GONE);
+        }
+        int numGroups = mGroups.size();
+        for (int i = 0; i < numGroups; i++) {
+            MessagingGroup group = mGroups.get(i);
+            int visibleChildren = 0;
+            List<MessagingMessage> messages = group.getMessages();
+            int numGroupMessages = messages.size();
+            for (int j = 0; j < numGroupMessages; j++) {
+                MessagingMessage message = messages.get(j);
+                if (message.getVisibility() != GONE) {
+                    visibleChildren++;
+                }
+            }
+            if (visibleChildren > 0 && group.getVisibility() == GONE) {
+                group.setVisibility(VISIBLE);
+            } else if (visibleChildren == 0 && group.getVisibility() != GONE)   {
+                group.setVisibility(GONE);
+            }
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (!mAddedGroups.isEmpty()) {
+            getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    for (MessagingGroup group : mAddedGroups) {
+                        if (!group.isShown()) {
+                            continue;
+                        }
+                        MessagingPropertyAnimator.fadeIn(group.getAvatar());
+                        MessagingPropertyAnimator.fadeIn(group.getSenderView());
+                        MessagingPropertyAnimator.startLocalTranslationFrom(group,
+                                group.getHeight(), LINEAR_OUT_SLOW_IN);
+                    }
+                    mAddedGroups.clear();
+                    getViewTreeObserver().removeOnPreDrawListener(this);
+                    return true;
+                }
+            });
+        }
+    }
+
+    public MessagingLinearLayout getMessagingLinearLayout() {
+        return mMessagingLinearLayout;
+    }
+
+    public ArrayList<MessagingGroup> getMessagingGroups() {
+        return mGroups;
+    }
+
+    private void updateExpandButton() {
+        int drawableId;
+        int contentDescriptionId;
+        int gravity;
+        int topMargin = 0;
+        ViewGroup newContainer;
+        int newContainerHeight;
+        if (mIsCollapsed) {
+            drawableId = R.drawable.ic_expand_notification;
+            contentDescriptionId = R.string.expand_button_content_description_collapsed;
+            gravity = Gravity.CENTER;
+            newContainer = mExpandButtonAndContentContainer;
+            newContainerHeight = LayoutParams.MATCH_PARENT;
+        } else {
+            drawableId = R.drawable.ic_collapse_notification;
+            contentDescriptionId = R.string.expand_button_content_description_expanded;
+            gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+            topMargin = mExpandButtonExpandedTopMargin;
+            newContainer = this;
+            newContainerHeight = mExpandButtonExpandedSize;
+        }
+        mExpandButton.setImageDrawable(getContext().getDrawable(drawableId));
+        mExpandButton.setColorFilter(mExpandButton.getOriginalNotificationColor());
+
+        // We need to make sure that the expand button is in the linearlayout pushing over the
+        // content when collapsed, but allows the content to flow under it when expanded.
+        if (newContainer != mExpandButtonContainer.getParent()) {
+            ((ViewGroup) mExpandButtonContainer.getParent()).removeView(mExpandButtonContainer);
+            newContainer.addView(mExpandButtonContainer);
+            MarginLayoutParams layoutParams =
+                    (MarginLayoutParams) mExpandButtonContainer.getLayoutParams();
+            layoutParams.height = newContainerHeight;
+            mExpandButtonContainer.setLayoutParams(layoutParams);
+        }
+
+        // update if the expand button is centered
+        FrameLayout.LayoutParams layoutParams = (LayoutParams) mExpandButton.getLayoutParams();
+        layoutParams.gravity = gravity;
+        layoutParams.topMargin = topMargin;
+        mExpandButton.setLayoutParams(layoutParams);
+
+        mExpandButtonContainer.setContentDescription(mContext.getText(contentDescriptionId));
+    }
+
+    private void updateContentPaddings() {
+
+        // Let's make sure the conversation header can't run into the expand button when we're
+        // collapsed and update the paddings of the content
+        int headerPaddingEnd;
+        int contentPaddingEnd;
+        if (!mExpandable) {
+            headerPaddingEnd = 0;
+            contentPaddingEnd = mContentMarginEnd;
+        } else if (mIsCollapsed) {
+            headerPaddingEnd = 0;
+            contentPaddingEnd = 0;
+        } else {
+            headerPaddingEnd = mNotificationHeaderExpandedPadding;
+            contentPaddingEnd = mContentMarginEnd;
+        }
+        mConversationHeader.setPaddingRelative(
+                mConversationHeader.getPaddingStart(),
+                mConversationHeader.getPaddingTop(),
+                headerPaddingEnd,
+                mConversationHeader.getPaddingBottom());
+
+        mContentContainer.setPaddingRelative(
+                mContentContainer.getPaddingStart(),
+                mContentContainer.getPaddingTop(),
+                contentPaddingEnd,
+                mContentContainer.getPaddingBottom());
+    }
+
+    public void updateExpandability(boolean expandable, @Nullable OnClickListener onClickListener) {
+        mExpandable = expandable;
+        if (expandable) {
+            mExpandButtonContainer.setVisibility(VISIBLE);
+            mExpandButtonContainer.setOnClickListener(onClickListener);
+        } else {
+            // TODO: handle content paddings to end of layout
+            mExpandButtonContainer.setVisibility(GONE);
+        }
+        updateContentPaddings();
+    }
+}
diff --git a/core/java/com/android/internal/widget/IMessagingLayout.java b/core/java/com/android/internal/widget/IMessagingLayout.java
new file mode 100644
index 0000000..149d056
--- /dev/null
+++ b/core/java/com/android/internal/widget/IMessagingLayout.java
@@ -0,0 +1,42 @@
+/*
+ * 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.internal.widget;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+
+/**
+ * An interface for a MessagingLayout
+ */
+public interface IMessagingLayout {
+
+    /**
+     * @return the layout containing the messages
+     */
+    MessagingLinearLayout getMessagingLinearLayout();
+
+    /**
+     * @return the context of this view
+     */
+    Context getContext();
+
+    /**
+     * @return the list of messaging groups
+     */
+    ArrayList<MessagingGroup> getMessagingGroups();
+}
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index c9a9161..c68da97 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -55,8 +55,9 @@
     private static Pools.SimplePool<MessagingGroup> sInstancePool
             = new Pools.SynchronizedPool<>(10);
     private MessagingLinearLayout mMessageContainer;
-    private ImageFloatingTextView mSenderName;
+    ImageFloatingTextView mSenderView;
     private ImageView mAvatarView;
+    private View mAvatarContainer;
     private String mAvatarSymbol = "";
     private int mLayoutColor;
     private CharSequence mAvatarName = "";
@@ -72,10 +73,22 @@
     private boolean mImagesAtEnd;
     private ViewGroup mImageContainer;
     private MessagingImageMessage mIsolatedMessage;
-    private boolean mTransformingImages;
+    private boolean mClippingDisabled;
     private Point mDisplaySize = new Point();
     private ProgressBar mSendingSpinner;
     private View mSendingSpinnerContainer;
+    private boolean mShowingAvatar = true;
+    private CharSequence mSenderName;
+    private boolean mSingleLine = false;
+    private LinearLayout mContentContainer;
+    private int mRequestedMaxDisplayedLines = Integer.MAX_VALUE;
+    private int mSenderTextPaddingSingleLine;
+    private boolean mIsFirstGroupInLayout = true;
+    private boolean mCanHideSenderIfFirst;
+    private boolean mIsInConversation = true;
+    private ViewGroup mMessagingIconContainer;
+    private int mConversationContentStart;
+    private int mNonConversationMarginEnd;
 
     public MessagingGroup(@NonNull Context context) {
         super(context);
@@ -99,26 +112,39 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mMessageContainer = findViewById(R.id.group_message_container);
-        mSenderName = findViewById(R.id.message_name);
+        mSenderView = findViewById(R.id.message_name);
         mAvatarView = findViewById(R.id.message_icon);
         mImageContainer = findViewById(R.id.messaging_group_icon_container);
         mSendingSpinner = findViewById(R.id.messaging_group_sending_progress);
+        mMessagingIconContainer = findViewById(R.id.message_icon_container);
+        mContentContainer = findViewById(R.id.messaging_group_content_container);
         mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container);
         DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
         mDisplaySize.x = displayMetrics.widthPixels;
         mDisplaySize.y = displayMetrics.heightPixels;
+        mSenderTextPaddingSingleLine = getResources().getDimensionPixelSize(
+                R.dimen.messaging_group_singleline_sender_padding_end);
+        mConversationContentStart = getResources().getDimensionPixelSize(
+                R.dimen.conversation_content_start);
+        mNonConversationMarginEnd = getResources().getDimensionPixelSize(
+                R.dimen.messaging_layout_margin_end);
     }
 
     public void updateClipRect() {
         // We want to clip to the senderName if it's available, otherwise our images will come
         // from a weird position
         Rect clipRect;
-        if (mSenderName.getVisibility() != View.GONE && !mTransformingImages) {
-            ViewGroup parent = (ViewGroup) mSenderName.getParent();
-            int top = getDistanceFromParent(mSenderName, parent) - getDistanceFromParent(
-                    mMessageContainer, parent) + mSenderName.getHeight();
+        if (mSenderView.getVisibility() != View.GONE && !mClippingDisabled) {
+            int top;
+            if (mSingleLine) {
+                top = 0;
+            } else {
+                top = getDistanceFromParent(mSenderView, mContentContainer)
+                        - getDistanceFromParent(mMessageContainer, mContentContainer)
+                        + mSenderView.getHeight();
+            }
             int size = Math.max(mDisplaySize.x, mDisplaySize.y);
-            clipRect = new Rect(0, top, size, size);
+            clipRect = new Rect(-size, top, size, size);
         } else {
             clipRect = null;
         }
@@ -140,17 +166,31 @@
         if (nameOverride == null) {
             nameOverride = sender.getName();
         }
-        mSenderName.setText(nameOverride);
+        mSenderName = nameOverride;
+        if (mSingleLine && !TextUtils.isEmpty(nameOverride)) {
+            nameOverride = mContext.getResources().getString(
+                    R.string.conversation_single_line_name_display, nameOverride);
+        }
+        mSenderView.setText(nameOverride);
         mNeedsGeneratedAvatar = sender.getIcon() == null;
         if (!mNeedsGeneratedAvatar) {
             setAvatar(sender.getIcon());
         }
-        mAvatarView.setVisibility(VISIBLE);
-        mSenderName.setVisibility(TextUtils.isEmpty(nameOverride) ? GONE : VISIBLE);
+        updateSenderVisibility();
+    }
+
+    /**
+     * Should the avatar be shown for this view.
+     *
+     * @param showingAvatar should it be shown
+     */
+    public void setShowingAvatar(boolean showingAvatar) {
+        mAvatarView.setVisibility(showingAvatar ? VISIBLE : GONE);
+        mShowingAvatar = showingAvatar;
     }
 
     public void setSending(boolean sending) {
-        int visibility = sending ? View.VISIBLE : View.GONE;
+        int visibility = sending ? VISIBLE : GONE;
         if (mSendingSpinnerContainer.getVisibility() != visibility) {
             mSendingSpinnerContainer.setVisibility(visibility);
             updateMessageColor();
@@ -171,7 +211,9 @@
 
     public void setAvatar(Icon icon) {
         mAvatarIcon = icon;
-        mAvatarView.setImageIcon(icon);
+        if (mShowingAvatar || icon == null) {
+            mAvatarView.setImageIcon(icon);
+        }
         mAvatarSymbol = "";
         mAvatarName = "";
     }
@@ -220,13 +262,20 @@
         setAvatar(null);
         mAvatarView.setAlpha(1.0f);
         mAvatarView.setTranslationY(0.0f);
-        mSenderName.setAlpha(1.0f);
-        mSenderName.setTranslationY(0.0f);
+        mSenderView.setAlpha(1.0f);
+        mSenderView.setTranslationY(0.0f);
         setAlpha(1.0f);
         mIsolatedMessage = null;
         mMessages = null;
+        mSenderName = null;
         mAddedMessages.clear();
         mFirstLayout = true;
+        setCanHideSenderIfFirst(false);
+        setIsFirstInLayout(true);
+
+        setMaxDisplayedLines(Integer.MAX_VALUE);
+        setSingleLine(false);
+        setShowingAvatar(true);
         MessagingPropertyAnimator.recycle(this);
         sInstancePool.release(MessagingGroup.this);
     }
@@ -252,7 +301,7 @@
     }
 
     public CharSequence getSenderName() {
-        return mSenderName.getText();
+        return mSenderName;
     }
 
     public static void dropCache() {
@@ -310,7 +359,12 @@
 
     @Override
     public void setMaxDisplayedLines(int lines) {
-        mMessageContainer.setMaxDisplayedLines(lines);
+        mRequestedMaxDisplayedLines = lines;
+        updateMaxDisplayedLines();
+    }
+
+    private void updateMaxDisplayedLines() {
+        mMessageContainer.setMaxDisplayedLines(mSingleLine ? 1 : mRequestedMaxDisplayedLines);
     }
 
     @Override
@@ -324,6 +378,35 @@
         return mIsHidingAnimated;
     }
 
+    @Override
+    public void setIsFirstInLayout(boolean first) {
+        if (first != mIsFirstGroupInLayout) {
+            mIsFirstGroupInLayout = first;
+            updateSenderVisibility();
+        }
+    }
+
+    /**
+     * @param canHide true if the sender can be hidden if it is first
+     */
+    public void setCanHideSenderIfFirst(boolean canHide) {
+        if (mCanHideSenderIfFirst != canHide) {
+            mCanHideSenderIfFirst = canHide;
+            updateSenderVisibility();
+        }
+    }
+
+    private void updateSenderVisibility() {
+        boolean hidden = (mIsFirstGroupInLayout || mSingleLine) && mCanHideSenderIfFirst
+                || TextUtils.isEmpty(mSenderName);
+        mSenderView.setVisibility(hidden ? GONE : VISIBLE);
+    }
+
+    @Override
+    public boolean hasDifferentHeightWhenFirst() {
+        return mCanHideSenderIfFirst && !mSingleLine && !TextUtils.isEmpty(mSenderName);
+    }
+
     private void setIsHidingAnimated(boolean isHiding) {
         ViewParent parent = getParent();
         mIsHidingAnimated = isHiding;
@@ -362,7 +445,7 @@
         mTextColor = messageTextColor;
         mSendingTextColor = calculateSendingTextColor();
         updateMessageColor();
-        mSenderName.setTextColor(senderTextColor);
+        mSenderView.setTextColor(senderTextColor);
     }
 
     public void setLayoutColor(int layoutColor) {
@@ -506,13 +589,17 @@
     }
 
     public View getSenderView() {
-        return mSenderName;
+        return mSenderView;
     }
 
     public View getAvatar() {
         return mAvatarView;
     }
 
+    public Icon getAvatarIcon() {
+        return mAvatarIcon;
+    }
+
     public MessagingLinearLayout getMessageContainer() {
         return mMessageContainer;
     }
@@ -529,8 +616,8 @@
         return mSender;
     }
 
-    public void setTransformingImages(boolean transformingImages) {
-        mTransformingImages = transformingImages;
+    public void setClippingDisabled(boolean disabled) {
+        mClippingDisabled = disabled;
     }
 
     public void setDisplayImagesAtEnd(boolean atEnd) {
@@ -543,4 +630,44 @@
     public List<MessagingMessage> getMessages() {
         return mMessages;
     }
+
+    /**
+     * Set this layout to be single line and therefore displaying both the sender and the text on
+     * the same line.
+     *
+     * @param singleLine should be layout be single line
+     */
+    public void setSingleLine(boolean singleLine) {
+        if (singleLine != mSingleLine) {
+            mSingleLine = singleLine;
+            mContentContainer.setOrientation(
+                    singleLine ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
+            MarginLayoutParams layoutParams = (MarginLayoutParams) mSenderView.getLayoutParams();
+            layoutParams.setMarginEnd(singleLine ? mSenderTextPaddingSingleLine : 0);
+            updateMaxDisplayedLines();
+            updateClipRect();
+            updateSenderVisibility();
+        }
+    }
+
+    public boolean isSingleLine() {
+        return mSingleLine;
+    }
+
+    /**
+     * Set this group to be displayed in a conversation and adjust the visual appearance
+     *
+     * @param isInConversation is this in a conversation
+     */
+    public void setIsInConversation(boolean isInConversation) {
+        if (mIsInConversation != isInConversation) {
+            mIsInConversation = isInConversation;
+            MarginLayoutParams layoutParams =
+                    (MarginLayoutParams) mMessagingIconContainer.getLayoutParams();
+            layoutParams.width = mIsInConversation ? mConversationContentStart
+                    : ViewPager.LayoutParams.WRAP_CONTENT;
+            layoutParams.setMarginEnd(mIsInConversation ? 0 : mNonConversationMarginEnd);
+            mMessagingIconContainer.setLayoutParams(layoutParams);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 64650a7..c243f3b 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -120,7 +120,7 @@
         return true;
     }
 
-    static MessagingMessage createMessage(MessagingLayout layout,
+    static MessagingMessage createMessage(IMessagingLayout layout,
             Notification.MessagingStyle.Message m, ImageResolver resolver) {
         MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
         MessagingImageMessage createdMessage = sInstancePool.acquire();
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index f608958..3fb5d43 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -58,7 +58,8 @@
  * messages and adapts the layout accordingly.
  */
 @RemoteViews.RemoteView
-public class MessagingLayout extends FrameLayout implements ImageMessageConsumer {
+public class MessagingLayout extends FrameLayout
+        implements ImageMessageConsumer, IMessagingLayout {
 
     private static final float COLOR_SHIFT_AMOUNT = 60;
     /**
@@ -143,9 +144,29 @@
         mNameReplacement = nameReplacement;
     }
 
+    /**
+     * Set this layout to show the collapsed representation.
+     *
+     * @param isCollapsed is it collapsed
+     */
     @RemotableViewMethod
-    public void setDisplayImagesAtEnd(boolean atEnd) {
-        mDisplayImagesAtEnd = atEnd;
+    public void setIsCollapsed(boolean isCollapsed) {
+        mDisplayImagesAtEnd = isCollapsed;
+    }
+
+    @RemotableViewMethod
+    public void setLargeIcon(Icon largeIcon) {
+        // Unused
+    }
+
+    /**
+     * Sets the conversation title of this conversation.
+     *
+     * @param conversationTitle the conversation title
+     */
+    @RemotableViewMethod
+    public void setConversationTitle(CharSequence conversationTitle) {
+        // Unused
     }
 
     @RemotableViewMethod
@@ -371,6 +392,15 @@
         mSenderTextColor = color;
     }
 
+
+    /**
+     * @param color the color of the notification background
+     */
+    @RemotableViewMethod
+    public void setNotificationBackgroundColor(int color) {
+        // Nothing to do with this
+    }
+
     @RemotableViewMethod
     public void setMessageTextColor(int color) {
         mMessageTextColor = color;
@@ -418,6 +448,7 @@
                 mAddedGroups.add(newGroup);
             }
             newGroup.setDisplayImagesAtEnd(mDisplayImagesAtEnd);
+            newGroup.setIsInConversation(false);
             newGroup.setLayoutColor(mLayoutColor);
             newGroup.setTextColors(mSenderTextColor, mMessageTextColor);
             Person sender = senders.get(groupIndex);
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 0c8613b..ac04862 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -43,7 +43,7 @@
 
     private int mMaxDisplayedLines = Integer.MAX_VALUE;
 
-    private MessagingLayout mMessagingLayout;
+    private IMessagingLayout mMessagingLayout;
 
     public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -84,6 +84,11 @@
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             lp.hide = true;
+            if (child instanceof MessagingChild) {
+                MessagingChild messagingChild = (MessagingChild) child;
+                // Whenever we encounter the message first, it's always first in the layout
+                messagingChild.setIsFirstInLayout(true);
+            }
         }
 
         totalHeight = mPaddingTop + mPaddingBottom;
@@ -91,6 +96,11 @@
         int linesRemaining = mMaxDisplayedLines;
         // Starting from the bottom: we measure every view as if it were the only one. If it still
         // fits, we take it, otherwise we stop there.
+        MessagingChild previousChild = null;
+        View previousView = null;
+        int previousChildHeight = 0;
+        int previousTotalHeight = 0;
+        int previousLinesConsumed = 0;
         for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
             if (getChildAt(i).getVisibility() == GONE) {
                 continue;
@@ -99,7 +109,16 @@
             LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
             MessagingChild messagingChild = null;
             int spacing = mSpacing;
+            int previousChildIncrease = 0;
             if (child instanceof MessagingChild) {
+                // We need to remeasure the previous child again if it's not the first anymore
+                if (previousChild != null && previousChild.hasDifferentHeightWhenFirst()) {
+                    previousChild.setIsFirstInLayout(false);
+                    measureChildWithMargins(previousView, widthMeasureSpec, 0, heightMeasureSpec,
+                            previousTotalHeight - previousChildHeight);
+                    previousChildIncrease = previousView.getMeasuredHeight() - previousChildHeight;
+                    linesRemaining -= previousChild.getConsumedLines() - previousLinesConsumed;
+                }
                 messagingChild = (MessagingChild) child;
                 messagingChild.setMaxDisplayedLines(linesRemaining);
                 spacing += messagingChild.getExtraSpacing();
@@ -110,18 +129,26 @@
 
             final int childHeight = child.getMeasuredHeight();
             int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
-                    lp.bottomMargin + spacing);
+                    lp.bottomMargin + spacing + previousChildIncrease);
             int measureType = MessagingChild.MEASURED_NORMAL;
             if (messagingChild != null) {
                 measureType = messagingChild.getMeasuredType();
-                linesRemaining -= messagingChild.getConsumedLines();
             }
 
             // We never measure the first item as too small, we want to at least show something.
             boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL && !first;
             boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED
                     || measureType == MessagingChild.MEASURED_TOO_SMALL && first;
-            if (newHeight <= targetHeight && !isTooSmall) {
+            boolean showView = newHeight <= targetHeight && !isTooSmall;
+            if (showView) {
+                if (messagingChild != null) {
+                    previousLinesConsumed = messagingChild.getConsumedLines();
+                    linesRemaining -= previousLinesConsumed;
+                    previousChild = messagingChild;
+                    previousView = child;
+                    previousChildHeight = childHeight;
+                    previousTotalHeight = totalHeight;
+                }
                 totalHeight = newHeight;
                 measuredWidth = Math.max(measuredWidth,
                         child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
@@ -131,6 +158,16 @@
                     break;
                 }
             } else {
+                // We now became too short, let's make sure to reset any previous views to be first
+                // and remeasure it.
+                if (previousChild != null && previousChild.hasDifferentHeightWhenFirst()) {
+                    previousChild.setIsFirstInLayout(true);
+                    // We need to remeasure the previous child again since it became first
+                    measureChildWithMargins(previousView, widthMeasureSpec, 0, heightMeasureSpec,
+                            previousTotalHeight - previousChildHeight);
+                    // The totalHeight is already correct here since we only set it during the
+                    // first pass
+                }
                 break;
             }
             first = false;
@@ -255,11 +292,11 @@
         mMaxDisplayedLines = numberLines;
     }
 
-    public void setMessagingLayout(MessagingLayout layout) {
+    public void setMessagingLayout(IMessagingLayout layout) {
         mMessagingLayout = layout;
     }
 
-    public MessagingLayout getMessagingLayout() {
+    public IMessagingLayout getMessagingLayout() {
         return mMessagingLayout;
     }
 
@@ -273,6 +310,20 @@
         void setMaxDisplayedLines(int lines);
         void hideAnimated();
         boolean isHidingAnimated();
+
+        /**
+         * Set that this view is first in layout. Relevant and only set if
+         * {@link #hasDifferentHeightWhenFirst()}.
+         * @param first is this first?
+         */
+        default void setIsFirstInLayout(boolean first) {}
+
+        /**
+         * @return if this layout has different height it is first in the layout
+         */
+        default boolean hasDifferentHeightWhenFirst() {
+            return false;
+        }
         default int getExtraSpacing() {
             return 0;
         }
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index c32d370..8c84379 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -32,7 +32,7 @@
      **/
     String IMAGE_MIME_TYPE_PREFIX = "image/";
 
-    static MessagingMessage createMessage(MessagingLayout layout,
+    static MessagingMessage createMessage(IMessagingLayout layout,
             Notification.MessagingStyle.Message m, ImageResolver resolver) {
         if (hasImage(m) && !ActivityManager.isLowRamDeviceStatic()) {
             return MessagingImageMessage.createMessage(layout, m, resolver);
diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java
index 4081a86..d778c59 100644
--- a/core/java/com/android/internal/widget/MessagingTextMessage.java
+++ b/core/java/com/android/internal/widget/MessagingTextMessage.java
@@ -26,14 +26,10 @@
 import android.util.AttributeSet;
 import android.util.Pools;
 import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
 
-import java.util.Objects;
-
 /**
  * A message of a {@link MessagingLayout}.
  */
@@ -74,7 +70,7 @@
         return true;
     }
 
-    static MessagingMessage createMessage(MessagingLayout layout,
+    static MessagingMessage createMessage(IMessagingLayout layout,
             Notification.MessagingStyle.Message m) {
         MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
         MessagingTextMessage createdMessage = sInstancePool.acquire();
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 39f82a5..a499806 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -20,7 +20,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.View;
+import android.view.RemotableViewMethod;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.Button;
 import android.widget.ImageView;
@@ -32,6 +32,8 @@
 @RemoteViews.RemoteView
 public class NotificationExpandButton extends ImageView {
 
+    private int mOriginalNotificationColor;
+
     public NotificationExpandButton(Context context) {
         super(context);
     }
@@ -56,6 +58,15 @@
         extendRectToMinTouchSize(outRect);
     }
 
+    @RemotableViewMethod
+    public void setOriginalNotificationColor(int color) {
+        mOriginalNotificationColor = color;
+    }
+
+    public int getOriginalNotificationColor() {
+        return mOriginalNotificationColor;
+    }
+
     private void extendRectToMinTouchSize(Rect rect) {
         int touchTargetSize = (int) (getResources().getDisplayMetrics().density * 48);
         rect.left = rect.centerX() - touchTargetSize / 2;
diff --git a/core/java/com/android/internal/widget/RemeasuringLinearLayout.java b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
index e352b45..7b154a5 100644
--- a/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
+++ b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
@@ -23,6 +23,8 @@
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 
+import java.util.ArrayList;
+
 /**
  * A LinearLayout that sets it's height again after the last measure pass. This is needed for
  * MessagingLayouts where groups need to be able to snap it's height to.
@@ -30,6 +32,8 @@
 @RemoteViews.RemoteView
 public class RemeasuringLinearLayout extends LinearLayout {
 
+    private ArrayList<View> mMatchParentViews = new ArrayList<>();
+
     public RemeasuringLinearLayout(Context context) {
         super(context);
     }
@@ -53,6 +57,8 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         int count = getChildCount();
         int height = 0;
+        boolean isVertical = getOrientation() == LinearLayout.VERTICAL;
+        boolean isWrapContent = getLayoutParams().height == LayoutParams.WRAP_CONTENT;
         for (int i = 0; i < count; ++i) {
             final View child = getChildAt(i);
             if (child == null || child.getVisibility() == View.GONE) {
@@ -60,9 +66,25 @@
             }
 
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            height = Math.max(height, height + child.getMeasuredHeight() + lp.topMargin +
-                    lp.bottomMargin);
+            if (!isWrapContent || lp.height != LayoutParams.MATCH_PARENT || isVertical) {
+                int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
+                height = Math.max(height, isVertical ? height + childHeight : childHeight);
+            } else {
+                // We have match parent children in a wrap content view, let's measure the
+                // view properly
+                mMatchParentViews.add(child);
+            }
         }
+        if (mMatchParentViews.size() > 0) {
+            int exactHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+            for (View child : mMatchParentViews) {
+                child.measure(getChildMeasureSpec(
+                        widthMeasureSpec, getPaddingStart() + getPaddingEnd(),
+                        child.getLayoutParams().width),
+                        exactHeightSpec);
+            }
+        }
+        mMatchParentViews.clear();
         setMeasuredDimension(getMeasuredWidth(), height);
     }
 }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 2128f99..ea3c0fa 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -121,16 +121,11 @@
 static pid_t gSystemServerPid = 0;
 
 static constexpr const char* kPropFuse = "persist.sys.fuse";
-static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote";
-
+static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
 static jclass gZygoteClass;
 static jmethodID gCallPostForkSystemServerHooks;
 static jmethodID gCallPostForkChildHooks;
 
-static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
-static jclass gZygoteInitClass;
-static jmethodID gCreateSystemServerClassLoader;
-
 static bool gIsSecurityEnforced = true;
 
 /**
@@ -356,10 +351,14 @@
 
 // Must match values in com.android.internal.os.Zygote.
 enum RuntimeFlags : uint32_t {
-  DEBUG_ENABLE_JDWP = 1,
-  PROFILE_FROM_SHELL = 1 << 15,
-  MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20),
-  MEMORY_TAG_LEVEL_TBI = 1 << 19,
+    DEBUG_ENABLE_JDWP = 1,
+    PROFILE_FROM_SHELL = 1 << 15,
+    MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20),
+    MEMORY_TAG_LEVEL_TBI = 1 << 19,
+    GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22),
+    GWP_ASAN_LEVEL_NEVER = 0 << 21,
+    GWP_ASAN_LEVEL_LOTTERY = 1 << 21,
+    GWP_ASAN_LEVEL_ALWAYS = 2 << 21,
 };
 
 enum UnsolicitedZygoteMessageTypes : uint32_t {
@@ -1568,23 +1567,6 @@
   auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
   const userid_t user_id = multiuser_get_user_id(uid);
 
-  // If FUSE is not ready for this user, skip it
-  // TODO(148772775): Pass primary volume name from zygote argument to here
-  std::string tmp = GetProperty("vold.fuse_running_users", "");
-  std::istringstream fuse_running_users(tmp);
-  bool user_found = false;
-  std::string s;
-  std::string user_id_str = std::to_string(user_id);
-  while (!user_found && std::getline(fuse_running_users, s, ',')) {
-    if (user_id_str == s) {
-      user_found = true;
-    }
-  }
-  if (!user_found) {
-    ALOGI("User %d is not running fuse yet, fuse_running_users=%s", user_id, tmp.c_str());
-    return;
-  }
-
   // Fuse is ready, so we can start using fuse path.
   int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
 
@@ -1612,7 +1594,7 @@
                              jstring managed_nice_name, bool is_system_server,
                              bool is_child_zygote, jstring managed_instruction_set,
                              jstring managed_app_data_dir, bool is_top_app,
-                             jobjectArray pkg_data_info_list) {
+                             jobjectArray pkg_data_info_list, bool mount_storage_dirs) {
   const char* process_name = is_system_server ? "system_server" : "zygote";
   auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
   auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1651,10 +1633,7 @@
     isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
     isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
   }
-
-  if ((mount_external != MOUNT_EXTERNAL_INSTALLER) &&
-        GetBoolProperty(kPropFuse, false) &&
-        GetBoolProperty(ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+  if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && mount_storage_dirs) {
     BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
   }
 
@@ -1741,6 +1720,18 @@
   }
   android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
 
+  bool forceEnableGwpAsan = false;
+  switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
+      default:
+      case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
+          break;
+      case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
+          forceEnableGwpAsan = true;
+          [[fallthrough]];
+      case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
+          android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
+  }
+
   if (NeedsNoRandomizeWorkaround()) {
     // Work around ARM kernel ASLR lossage (http://b/5817320).
     int old_personality = personality(0xffffffff);
@@ -1780,15 +1771,6 @@
       fail_fn("Error calling post fork system server hooks.");
     }
 
-    // Prefetch the classloader for the system server. This is done early to
-    // allow a tie-down of the proper system server selinux domain.
-    env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader);
-    if (env->ExceptionCheck()) {
-      // Be robust here. The Java code will attempt to create the classloader
-      // at a later point (but may not have rights to use AoT artifacts).
-      env->ExceptionClear();
-    }
-
     // TODO(oth): Remove hardcoded label here (b/117874058).
     static const char* kSystemServerLabel = "u:r:system_server:s0";
     if (selinux_android_setcon(kSystemServerLabel) != 0) {
@@ -2021,7 +2003,7 @@
         jint mount_external, jstring se_info, jstring nice_name,
         jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
         jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
-        jobjectArray pkg_data_info_list) {
+        jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
     if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -2058,7 +2040,8 @@
                        capabilities, capabilities,
                        mount_external, se_info, nice_name, false,
                        is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                       is_top_app == JNI_TRUE, pkg_data_info_list);
+                       is_top_app == JNI_TRUE, pkg_data_info_list,
+                       mount_storage_dirs == JNI_TRUE);
     }
     return pid;
 }
@@ -2093,7 +2076,7 @@
                        permitted_capabilities, effective_capabilities,
                        MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
                        false, nullptr, nullptr, /* is_top_app= */ false,
-                       /* pkg_data_info_list */ nullptr);
+                       /* pkg_data_info_list */ nullptr, false);
   } else if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -2223,14 +2206,15 @@
     jint runtime_flags, jobjectArray rlimits,
     jint mount_external, jstring se_info, jstring nice_name,
     jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
-    jobjectArray pkg_data_info_list) {
+    jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
   jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
   SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                    capabilities, capabilities,
                    mount_external, se_info, nice_name, false,
                    is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                   is_top_app == JNI_TRUE, pkg_data_info_list);
+                   is_top_app == JNI_TRUE, pkg_data_info_list,
+                   mount_storage_dirs == JNI_TRUE);
 }
 
 /**
@@ -2424,7 +2408,7 @@
 static const JNINativeMethod gMethods[] = {
         {"nativeForkAndSpecialize",
          "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
-         "String;Z[Ljava/lang/String;)I",
+         "String;Z[Ljava/lang/String;Z)I",
          (void*)com_android_internal_os_Zygote_nativeForkAndSpecialize},
         {"nativeForkSystemServer", "(II[II[[IJJ)I",
          (void*)com_android_internal_os_Zygote_nativeForkSystemServer},
@@ -2437,7 +2421,7 @@
         {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
         {"nativeSpecializeAppProcess",
          "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
-         "String;Z[Ljava/lang/String;)V",
+         "String;Z[Ljava/lang/String;Z)V",
          (void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess},
         {"nativeInitNativeState", "(Z)V",
          (void*)com_android_internal_os_Zygote_nativeInitNativeState},
@@ -2466,13 +2450,6 @@
   gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
                                                    "(IZZLjava/lang/String;)V");
 
-  gZygoteInitClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteInitClassName));
-  gCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass,
-                                                          "createSystemServerClassLoader",
-                                                          "()V");
-
-  RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
-
-  return JNI_OK;
+  return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
 }
 }  // namespace android
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
index 9abe923..42437d5b 100644
--- a/core/proto/android/app/enums.proto
+++ b/core/proto/android/app/enums.proto
@@ -104,3 +104,108 @@
     PROCESS_STATE_NONEXISTENT = 1019;
 }
 
+// AppOpsManager.java - operation ids for logging
+enum AppOpEnum {
+    APP_OP_NONE = -1;
+    APP_OP_COARSE_LOCATION = 0;
+    APP_OP_FINE_LOCATION = 1;
+    APP_OP_GPS = 2;
+    APP_OP_VIBRATE = 3;
+    APP_OP_READ_CONTACTS = 4;
+    APP_OP_WRITE_CONTACTS = 5;
+    APP_OP_READ_CALL_LOG = 6;
+    APP_OP_WRITE_CALL_LOG = 7;
+    APP_OP_READ_CALENDAR = 8;
+    APP_OP_WRITE_CALENDAR = 9;
+    APP_OP_WIFI_SCAN = 10;
+    APP_OP_POST_NOTIFICATION = 11;
+    APP_OP_NEIGHBORING_CELLS = 12;
+    APP_OP_CALL_PHONE = 13;
+    APP_OP_READ_SMS = 14;
+    APP_OP_WRITE_SMS = 15;
+    APP_OP_RECEIVE_SMS = 16;
+    APP_OP_RECEIVE_EMERGENCY_SMS = 17;
+    APP_OP_RECEIVE_MMS = 18;
+    APP_OP_RECEIVE_WAP_PUSH = 19;
+    APP_OP_SEND_SMS = 20;
+    APP_OP_READ_ICC_SMS = 21;
+    APP_OP_WRITE_ICC_SMS = 22;
+    APP_OP_WRITE_SETTINGS = 23;
+    APP_OP_SYSTEM_ALERT_WINDOW = 24;
+    APP_OP_ACCESS_NOTIFICATIONS = 25;
+    APP_OP_CAMERA = 26;
+    APP_OP_RECORD_AUDIO = 27;
+    APP_OP_PLAY_AUDIO = 28;
+    APP_OP_READ_CLIPBOARD = 29;
+    APP_OP_WRITE_CLIPBOARD = 30;
+    APP_OP_TAKE_MEDIA_BUTTONS = 31;
+    APP_OP_TAKE_AUDIO_FOCUS = 32;
+    APP_OP_AUDIO_MASTER_VOLUME = 33;
+    APP_OP_AUDIO_VOICE_VOLUME = 34;
+    APP_OP_AUDIO_RING_VOLUME = 35;
+    APP_OP_AUDIO_MEDIA_VOLUME = 36;
+    APP_OP_AUDIO_ALARM_VOLUME = 37;
+    APP_OP_AUDIO_NOTIFICATION_VOLUME = 38;
+    APP_OP_AUDIO_BLUETOOTH_VOLUME = 39;
+    APP_OP_WAKE_LOCK = 40;
+    APP_OP_MONITOR_LOCATION = 41;
+    APP_OP_MONITOR_HIGH_POWER_LOCATION = 42;
+    APP_OP_GET_USAGE_STATS = 43;
+    APP_OP_MUTE_MICROPHONE = 44;
+    APP_OP_TOAST_WINDOW = 45;
+    APP_OP_PROJECT_MEDIA = 46;
+    APP_OP_ACTIVATE_VPN = 47;
+    APP_OP_WRITE_WALLPAPER = 48;
+    APP_OP_ASSIST_STRUCTURE = 49;
+    APP_OP_ASSIST_SCREENSHOT = 50;
+    APP_OP_READ_PHONE_STATE = 51;
+    APP_OP_ADD_VOICEMAIL = 52;
+    APP_OP_USE_SIP = 53;
+    APP_OP_PROCESS_OUTGOING_CALLS = 54;
+    APP_OP_USE_FINGERPRINT = 55;
+    APP_OP_BODY_SENSORS = 56;
+    APP_OP_READ_CELL_BROADCASTS = 57;
+    APP_OP_MOCK_LOCATION = 58;
+    APP_OP_READ_EXTERNAL_STORAGE = 59;
+    APP_OP_WRITE_EXTERNAL_STORAGE = 60;
+    APP_OP_TURN_SCREEN_ON = 61;
+    APP_OP_GET_ACCOUNTS = 62;
+    APP_OP_RUN_IN_BACKGROUND = 63;
+    APP_OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
+    APP_OP_READ_PHONE_NUMBERS = 65;
+    APP_OP_REQUEST_INSTALL_PACKAGES = 66;
+    APP_OP_PICTURE_IN_PICTURE = 67;
+    APP_OP_INSTANT_APP_START_FOREGROUND = 68;
+    APP_OP_ANSWER_PHONE_CALLS = 69;
+    APP_OP_RUN_ANY_IN_BACKGROUND = 70;
+    APP_OP_CHANGE_WIFI_STATE = 71;
+    APP_OP_REQUEST_DELETE_PACKAGES = 72;
+    APP_OP_BIND_ACCESSIBILITY_SERVICE = 73;
+    APP_OP_ACCEPT_HANDOVER = 74;
+    APP_OP_MANAGE_IPSEC_TUNNELS = 75;
+    APP_OP_START_FOREGROUND = 76;
+    APP_OP_BLUETOOTH_SCAN = 77;
+    APP_OP_USE_BIOMETRIC = 78;
+    APP_OP_ACTIVITY_RECOGNITION = 79;
+    APP_OP_SMS_FINANCIAL_TRANSACTIONS = 80;
+    APP_OP_READ_MEDIA_AUDIO = 81;
+    APP_OP_WRITE_MEDIA_AUDIO = 82;
+    APP_OP_READ_MEDIA_VIDEO = 83;
+    APP_OP_WRITE_MEDIA_VIDEO = 84;
+    APP_OP_READ_MEDIA_IMAGES = 85;
+    APP_OP_WRITE_MEDIA_IMAGES = 86;
+    APP_OP_LEGACY_STORAGE = 87;
+    APP_OP_ACCESS_ACCESSIBILITY = 88;
+    APP_OP_READ_DEVICE_IDENTIFIERS = 89;
+    APP_OP_ACCESS_MEDIA_LOCATION = 90;
+    APP_OP_QUERY_ALL_PACKAGES = 91;
+    APP_OP_MANAGE_EXTERNAL_STORAGE = 92;
+    APP_OP_INTERACT_ACROSS_PROFILES = 93;
+    APP_OP_ACTIVATE_PLATFORM_VPN = 94;
+    APP_OP_LOADER_USAGE_STATS = 95;
+    APP_OP_ACCESS_CALL_AUDIO = 96;
+    APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
+    APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98;
+}
+
+
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 030483b..ef6eb38 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -724,6 +724,16 @@
     // CATEGORY: SETTINGS
     // OS: R
     ACTION_ADB_WIRELESS_OFF = 1735;
+
+    // ACTION: Change Wi-Fi hotspot name
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_NAME = 1736;
+
+    // ACTION: Change Wi-Fi hotspot password
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_PASSWORD = 1737;
 }
 
 /**
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index 4a7d043..e8ae1b3 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -109,6 +109,7 @@
         }
         optional int32 network_security_config_res = 17;
         optional int32 category = 18;
+        optional bool enable_gwp_asan = 19;
     }
     optional Detail detail = 17;
 }
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 3d8108d..684a292 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -153,7 +153,7 @@
   CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER = 126;
   SET_AUTO_TIME = 127;
   SET_AUTO_TIME_ZONE = 128;
-  SET_PACKAGES_PROTECTED = 129;
+  SET_USER_CONTROL_DISABLED_PACKAGES = 129;
   SET_FACTORY_RESET_PROTECTION = 130;
   SET_COMMON_CRITERIA_MODE = 131;
   ALLOW_MODIFICATION_OF_ADMIN_CONFIGURED_NETWORKS = 132;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 071bb11..7a3ec95 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3756,6 +3756,12 @@
     <permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS"
                 android:protectionLevel="signature|installer" />
 
+    <!-- @SystemApi Allows an application to an exempt an app from having its permission be
+        auto-revoked when unused for an extended period of time.
+        @hide -->
+    <permission android:name="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS"
+        android:protectionLevel="signature|installer" />
+
     <!-- @hide Allows an application to observe permission changes. -->
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
         android:protectionLevel="signature|privileged" />
@@ -5003,15 +5009,15 @@
     <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
                 android:protectionLevel="signature|appPredictor" />
 
-    <!-- Feature Id for Country Detector. -->
-    <feature android:featureId="CountryDetector" android:label="@string/country_detector"/>
-    <!-- Feature Id for Location service. -->
-    <feature android:featureId="LocationService" android:label="@string/location_service"/>
-    <!-- Feature Id for Sensor Notification service. -->
-    <feature android:featureId="SensorNotificationService"
+    <!-- Attribution for Country Detector. -->
+    <attribution android:tag="CountryDetector" android:label="@string/country_detector"/>
+    <!-- Attribution for Location service. -->
+    <attribution android:tag="LocationService" android:label="@string/location_service"/>
+    <!-- Attribution for Sensor Notification service. -->
+    <attribution android:tag="SensorNotificationService"
              android:label="@string/sensor_notification_service"/>
     <!-- Feature Id for Twilight service. -->
-    <feature android:featureId="TwilightService" android:label="@string/twilight_service"/>
+    <attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
 
     <application android:process="system"
                  android:persistent="true"
diff --git a/core/res/res/drawable/conversation_badge_background.xml b/core/res/res/drawable/conversation_badge_background.xml
new file mode 100644
index 0000000..0dd0dcd
--- /dev/null
+++ b/core/res/res/drawable/conversation_badge_background.xml
@@ -0,0 +1,28 @@
+<?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
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+    <solid
+        android:color="#ffffff"/>
+
+    <size
+        android:width="26dp"
+        android:height="26dp"/>
+</shape>
+
diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
index 124e99e..ca4f0ed 100644
--- a/core/res/res/drawable/ic_collapse_notification.xml
+++ b/core/res/res/drawable/ic_collapse_notification.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2015 The Android Open Source Project
+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.
@@ -15,11 +15,14 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14.0dp"
-        android:height="14.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="22.0dp"
+    android:height="22.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M12.0,8.0l-6.0,6.0l1.4,1.4l4.6,-4.6l4.6,4.6L18.0,14.0L12.0,8.0z"/>
-</vector>
+        android:pathData="M18.59,16.41L20.0,15.0l-8.0,-8.0 -8.0,8.0 1.41,1.41L12.0,9.83"/>
+    <path
+        android:pathData="M0 0h24v24H0V0z"
+        android:fillColor="#00000000"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
index 847e326..a080ce4 100644
--- a/core/res/res/drawable/ic_expand_notification.xml
+++ b/core/res/res/drawable/ic_expand_notification.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2015 The Android Open Source Project
+Copyright (C) 2014 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -15,11 +15,14 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14.0dp"
-        android:height="14.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+    android:width="22.0dp"
+    android:height="22.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M16.6,8.6L12.0,13.2L7.4,8.6L6.0,10.0l6.0,6.0l6.0,-6.0L16.6,8.6z"/>
-</vector>
+        android:pathData="M5.41,7.59L4.0,9.0l8.0,8.0 8.0,-8.0 -1.41,-1.41L12.0,14.17"/>
+    <path
+        android:pathData="M24 24H0V0h24v24z"
+        android:fillColor="#00000000"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/conversation_face_pile_layout.xml b/core/res/res/layout/conversation_face_pile_layout.xml
new file mode 100644
index 0000000..1db3870
--- /dev/null
+++ b/core/res/res/layout/conversation_face_pile_layout.xml
@@ -0,0 +1,45 @@
+<?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
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/conversation_face_pile"
+    android:layout_width="@dimen/conversation_avatar_size"
+    android:layout_height="@dimen/conversation_avatar_size"
+    android:forceHasOverlappingRendering="false"
+    >
+    <ImageView
+        android:id="@+id/conversation_face_pile_top"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:scaleType="centerCrop"
+        android:layout_gravity="end|top"
+        />
+    <FrameLayout
+        android:id="@+id/conversation_face_pile_bottom_background"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:layout_gravity="start|bottom"
+        android:background="@drawable/conversation_badge_background">
+        <ImageView
+            android:id="@+id/conversation_face_pile_bottom"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:scaleType="centerCrop"
+            android:layout_gravity="center"
+            />
+    </FrameLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index f5fa1b6a..6f36aae 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -91,7 +91,6 @@
         android:textAppearance="@style/TextAppearance.Material.Notification.Time"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
         android:layout_marginStart="@dimen/notification_header_separating_margin"
         android:layout_marginEnd="@dimen/notification_header_separating_margin"
         android:showRelative="true"
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
new file mode 100644
index 0000000..2348dee
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -0,0 +1,206 @@
+<?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
+  -->
+<com.android.internal.widget.ConversationLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:tag="conversation"
+    android:theme="@style/Theme.DeviceDefault.Notification"
+    >
+
+    <FrameLayout
+        android:layout_width="@dimen/conversation_content_start"
+        android:layout_height="wrap_content"
+        android:gravity="start|top"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:paddingTop="12dp"
+    >
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+        >
+
+            <!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right -->
+            <ImageView
+                android:id="@+id/conversation_icon"
+                android:layout_width="@dimen/conversation_avatar_size"
+                android:layout_height="@dimen/conversation_avatar_size"
+                android:scaleType="centerCrop"
+                android:importantForAccessibility="no"
+            />
+
+            <ViewStub
+                android:layout="@layout/conversation_face_pile_layout"
+                android:layout_width="@dimen/conversation_avatar_size"
+                android:layout_height="@dimen/conversation_avatar_size"
+                android:id="@+id/conversation_face_pile"
+                />
+
+            <FrameLayout
+                android:id="@+id/conversation_icon_badge"
+                android:layout_width="20dp"
+                android:layout_height="20dp"
+                android:layout_marginLeft="@dimen/conversation_badge_side_margin"
+                android:layout_marginTop="@dimen/conversation_badge_side_margin"
+                android:background="@drawable/conversation_badge_background" >
+                <!-- Badge: 20x20, 48dp padding left + top -->
+                <com.android.internal.widget.CachingIconView
+                    android:id="@+id/icon"
+                    android:layout_width="@dimen/conversation_icon_size_badged"
+                    android:layout_height="@dimen/conversation_icon_size_badged"
+                    android:layout_gravity="center"
+                />
+            </FrameLayout>
+        </FrameLayout>
+    </FrameLayout>
+
+    <!-- Wraps entire "expandable" notification -->
+    <com.android.internal.widget.RemeasuringLinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:clipToPadding="false"
+        android:clipChildren="false"
+        android:orientation="vertical"
+        >
+        <!-- LinearLayout for Expand Button-->
+        <com.android.internal.widget.RemeasuringLinearLayout
+            android:id="@+id/expand_button_and_content_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="start|top"
+            android:orientation="horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false">
+            <!--TODO: move this into a separate layout and share logic with the header to bring back app opps etc-->
+            <com.android.internal.widget.RemeasuringLinearLayout
+                android:id="@+id/notification_action_list_margin_target"
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_height="wrap_content"
+                android:layout_weight="1">
+
+                <!-- Header -->
+                <LinearLayout
+                    android:id="@+id/conversation_header"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:paddingTop="16dp"
+                    android:paddingStart="@dimen/conversation_content_start"
+                >
+                    <TextView
+                        android:id="@+id/conversation_text"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                        android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                        android:textSize="16sp"
+                        android:singleLine="true"
+                        />
+
+                    <TextView
+                        android:id="@+id/time_divider"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:textAppearance="?attr/notificationHeaderTextAppearance"
+                        android:layout_marginStart="@dimen/notification_header_separating_margin"
+                        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                        android:text="@string/notification_header_divider_symbol"
+                        android:layout_gravity="center"
+                        android:paddingTop="1sp"
+                        android:singleLine="true"
+                        android:visibility="gone"
+                    />
+
+                    <DateTimeView
+                        android:id="@+id/time"
+                        android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center"
+                        android:layout_marginStart="@dimen/notification_header_separating_margin"
+                        android:paddingTop="1sp"
+                        android:showRelative="true"
+                        android:singleLine="true"
+                        android:visibility="gone"
+                    />
+
+                    <ImageView
+                        android:id="@+id/profile_badge"
+                        android:layout_width="@dimen/notification_badge_size"
+                        android:layout_height="@dimen/notification_badge_size"
+                        android:layout_gravity="center"
+                        android:layout_marginStart="4dp"
+                        android:paddingTop="2dp"
+                        android:scaleType="fitCenter"
+                        android:visibility="gone"
+                        android:contentDescription="@string/notification_work_profile_content_description"
+                    />
+                </LinearLayout>
+
+                <!-- Messages -->
+                <com.android.internal.widget.MessagingLinearLayout
+                    android:id="@+id/notification_messaging"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="2dp"
+                    android:spacing="@dimen/notification_messaging_spacing"
+                    android:clipToPadding="false"
+                    android:clipChildren="false"
+                    />
+            </com.android.internal.widget.RemeasuringLinearLayout>
+            <!-- Unread Count -->
+            <!-- <TextView /> -->
+
+            <!-- This is where the expand button will be placed when collapsed-->
+        </com.android.internal.widget.RemeasuringLinearLayout>
+
+        <include layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            android:layout_marginStart="@dimen/conversation_content_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end" />
+        <include layout="@layout/notification_material_action_list" />
+    </com.android.internal.widget.RemeasuringLinearLayout>
+
+    <!--This is dynamically placed between here and at the end of the layout-->
+    <FrameLayout
+        android:id="@+id/expand_button_container"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/conversation_expand_button_expanded_size"
+        android:layout_gravity="end|top"
+        android:paddingStart="16dp"
+        android:paddingEnd="@dimen/notification_content_margin_end">
+        <com.android.internal.widget.NotificationExpandButton
+            android:id="@+id/expand_button"
+            android:layout_width="@dimen/notification_header_expand_icon_size"
+            android:layout_height="@dimen/notification_header_expand_icon_size"
+            android:layout_gravity="center"
+            android:drawable="@drawable/ic_expand_notification"
+            android:clickable="false"
+            android:importantForAccessibility="no"
+            />
+    </FrameLayout>
+</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 483b479..3188861 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -20,14 +20,20 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal" >
-    <ImageView
-        android:id="@+id/message_icon"
-        android:layout_width="@dimen/messaging_avatar_size"
-        android:layout_height="@dimen/messaging_avatar_size"
-        android:layout_marginEnd="12dp"
-        android:scaleType="centerCrop"
-        android:importantForAccessibility="no" />
+    <FrameLayout
+        android:id="@+id/message_icon_container"
+        android:layout_width="@dimen/conversation_content_start"
+        android:layout_height="wrap_content">
+        <ImageView
+            android:layout_gravity="top|center_horizontal"
+            android:id="@+id/message_icon"
+            android:layout_width="@dimen/messaging_avatar_size"
+            android:layout_height="@dimen/messaging_avatar_size"
+            android:scaleType="centerCrop"
+            android:importantForAccessibility="no" />
+    </FrameLayout>
     <com.android.internal.widget.RemeasuringLinearLayout
+        android:id="@+id/messaging_group_content_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_weight="1"
@@ -43,7 +49,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginTop="@dimen/notification_text_margin_top"
-            android:spacing="2dp"/>
+            android:spacing="2dp" />
     </com.android.internal.widget.RemeasuringLinearLayout>
     <FrameLayout
         android:id="@+id/messaging_group_icon_container"
diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml
index 619b392..176f289 100644
--- a/core/res/res/layout/resolver_empty_states.xml
+++ b/core/res/res/layout/resolver_empty_states.xml
@@ -38,7 +38,7 @@
         android:layout_height="wrap_content"
         android:fontFamily="@string/config_headlineFontFamilyMedium"
         android:textColor="@color/resolver_empty_state_text"
-        android:textSize="18sp"
+        android:textSize="14sp"
         android:layout_centerHorizontal="true" />
     <TextView
         android:id="@+id/resolver_empty_state_subtitle"
@@ -47,7 +47,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textColor="@color/resolver_empty_state_text"
-        android:textSize="14sp"
+        android:textSize="12sp"
         android:gravity="center_horizontal"
         android:layout_centerHorizontal="true" />
     <Button
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c245131..f3ca5ac 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1541,6 +1541,28 @@
         <flag name="microphone" value="0x80" />
     </attr>
 
+    <!-- Enable sampled memory bug detection in this process.
+         When enabled, a very small, random subset of native
+         memory allocations are protected with guard pages, providing an
+         ASan-like error report in case of a memory corruption bug.
+
+         GWP-ASan is a recursive acronym. It stands for “GWP-ASan Will Provide Allocation SANity”.
+         See the <a href="http://llvm.org/docs/GwpAsan.html">LLVM documentation</a>
+         for more information about this feature.
+
+         <p>This tag can be applied to any tag that allows
+         {@link android.R.styleable#AndroidManifestProcess process} tag:
+         {@link android.R.styleable#AndroidManifestApplication application} tag (to supply
+         a default setting for all application components), or with the
+         {@link android.R.styleable#AndroidManifestProvider provider},
+         {@link android.R.styleable#AndroidManifestService service},
+         {@link android.R.styleable#AndroidManifestReceiver receiver},
+         {@link android.R.styleable#AndroidManifestActivity activity} tag.
+         When multiple components run in the same process,
+         the first component to start determines the behavior of the entire process.
+
+         The default value is {@code false}. -->
+    <attr name="enableGwpAsan" format="boolean" />
 
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
@@ -1552,7 +1574,7 @@
          <code>com.google.app.<em>appname</em></code>
 
          <p>Inside of the manifest tag, may appear the following tags
-         in any order: {@link #AndroidManifestFeature feature},
+         in any order: {@link #AndroidManifestAttribution attribution},
          {@link #AndroidManifestPermission permission},
          {@link #AndroidManifestPermissionGroup permission-group},
          {@link #AndroidManifestPermissionTree permission-tree},
@@ -1806,31 +1828,51 @@
 
              The default value is {@code true}. -->
         <attr name="allowNativeHeapPointerTagging" format="boolean" />
+
+        <attr name="enableGwpAsan" />
+
+        <!-- If {@code true} allow requesting that its permissions don't get automatically
+             revoked when the app is unused for an extended amount of time.
+
+             The default value is {@code false}. -->
+        <attr name="requestDontAutoRevokePermissions" format="boolean" />
+
+        <!-- If {@code true} its permissions shouldn't get automatically
+             revoked when the app is unused for an extended amount of time.
+
+             This implies {@code requestDontAutoRevokePermissions=true}
+
+             The default value is {@code false}. -->
+        <attr name="allowDontAutoRevokePermissions" format="boolean" />
     </declare-styleable>
 
-    <!-- The <code>feature</code> tag declares a feature. A feature is a logical part of an app.
-    E.g. photo sharing app might include a direct messaging component. To tag certain code as
-    belonging to a feature, use a context created via
-    {@link android.content.Context#createFeatureContext(String)} for any interaction with the
+    <!-- An attribution is a logical part of an app and is identified by a tag.
+    E.g. a photo sharing app might include a direct messaging component. To tag certain code as
+    belonging to an attribution, use a context created via
+    {@link android.content.Context#createAttributionContext(String)} for any interaction with the
     system.
 
     <p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag.
 
-    <p>In case this feature inherits from another feature, this tag can contain one or multiple
-    {@link #AndroidManifestFeatureInheritFrom inherit-from} tags. -->
-    <declare-styleable name="AndroidManifestFeature" parent="AndroidManifest">
-        <!-- Required identifier for a feature. Can be passed to
-        {@link android.content.Context#createFeatureContext} to create a context for this feature
-        -->
+    <p>In case this attribution inherits from another attribution, this tag can contain one or
+    multiple {@link #AndroidManifestAttributionInheritFrom inherit-from} tags. -->
+    <declare-styleable name="AndroidManifestAttribution" parent="AndroidManifest">
+        <!-- TODO moltmann: Remove -->
         <attr name="featureId" format="string" />
-        <!-- Required user visible label for a feature. -->
+        <!-- Required identifier for a attribution. Can be passed to
+        {@link android.content.Context#createAttributionContext} to create a context tagged with
+        this attribution
+        -->
+        <attr name="tag" format="string" />
+        <!-- Required user visible label for a attribution. -->
         <attr name="label" format="string" />
     </declare-styleable>
 
     <!-- Declares previously declared features this feature inherits from. -->
-    <declare-styleable name="AndroidManifestFeatureInheritFrom" parent="AndroidManifestFeature">
-        <!-- Identifier of the feature this feature inherits from -->
-        <attr name="featureId" format="string" />
+    <declare-styleable name="AndroidManifestAttributionInheritFrom"
+                       parent="AndroidManifestAttribution">
+        <!-- Identifier of the attribution this attribution inherits from -->
+        <attr name="tag" format="string" />
     </declare-styleable>
 
     <!-- The <code>permission</code> tag declares a security permission that can be
@@ -2312,6 +2354,7 @@
     <declare-styleable name="AndroidManifestProcess" parent="AndroidManifestProcesses">
         <!-- Required name of the process that is allowed -->
         <attr name="process" />
+        <attr name="enableGwpAsan" />
     </declare-styleable>
 
     <!-- The <code>deny-permission</code> tag specifies that a permission is to be denied
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6f468e0..a2aa492 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4421,4 +4421,8 @@
 
     <!-- The max scale for the wallpaper when it's zoomed in -->
     <item name="config_wallpaperMaxScale" format="float" type="dimen">1</item>
+
+    <!-- Package name that will receive an explicit manifest broadcast for
+         android.os.action.POWER_SAVE_MODE_CHANGED. -->
+    <string name="config_powerSaveModeChangedListenerPackage" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2faa0c9..15ef09c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -682,7 +682,31 @@
     <!-- The size of the right icon image when on low ram -->
     <dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size</dimen>
 
-    <dimen name="messaging_avatar_size">52dp</dimen>
+    <dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen>
+    <dimen name="conversation_avatar_size">52dp</dimen>
+    <!-- Start of the content in the conversation template -->
+    <dimen name="conversation_content_start">80dp</dimen>
+    <!-- Size of the expand button when expanded -->
+    <dimen name="conversation_expand_button_expanded_size">80dp</dimen>
+    <!-- Top margin of the expand button for conversations when expanded -->
+    <dimen name="conversation_expand_button_top_margin_expanded">18dp</dimen>
+    <!-- Side margins of the conversation badge in relation to the conversation icon -->
+    <dimen name="conversation_badge_side_margin">36dp</dimen>
+    <!-- size of the notification icon when badged in a conversation -->
+    <dimen name="conversation_icon_size_badged">15dp</dimen>
+    <!-- size of the notification icon when centered in a conversation -->
+    <dimen name="conversation_icon_size_centered">20dp</dimen>
+    <!-- margin on the top when the icon is centered for group conversations -->
+    <dimen name="conversation_icon_margin_top_centered">5dp</dimen>
+
+    <!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
+    <dimen name="conversation_header_expanded_padding_end">38dp</dimen>
+
+    <!-- margin at the end of messaging group icons when not conversations -->
+    <dimen name="messaging_layout_margin_end">12dp</dimen>
+
+    <!-- Padding between text and sender when singleline -->
+    <dimen name="messaging_group_singleline_sender_padding_end">4dp</dimen>
 
     <dimen name="messaging_group_sending_progress_size">24dp</dimen>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 39e8197..7230cc4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3004,6 +3004,7 @@
       <public name="animatedImageDrawable"/>
       <public name="htmlDescription"/>
       <public name="preferMinimalPostProcessing"/>
+      <!-- @removed -->
       <public name="featureId" />
       <public name="supportsInlineSuggestions" />
       <public name="crossProfile" />
@@ -3013,8 +3014,11 @@
       <!-- @hide @SystemApi -->
       <public name="minExtensionVersion" />
       <public name="allowNativeHeapPointerTagging" />
+      <public name="requestDontAutoRevokePermissions" />
+      <public name="allowDontAutoRevokePermissions" />
       <public name="preserveLegacyExternalStorage" />
       <public name="mimeGroup" />
+      <public name="enableGwpAsan" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 789628d..f101f59 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5440,6 +5440,15 @@
     <string name="as_app_forced_to_restricted_bucket">
         <xliff:g id="package_name" example="com.android.example">%1$s</xliff:g> has been put into the RESTRICTED bucket</string>
 
+    <!-- The way a conversation name is displayed when single line. The text will be displayed to the end of this text with some spacing -->
+    <string name="conversation_single_line_name_display"><xliff:g id="sender_name" example="Sara">%1$s</xliff:g>:</string>
+
+    <!-- Conversation Title fallback if the there is no name provided in a 1:1 conversation [CHAR LIMIT=40]-->
+    <string name="conversation_title_fallback_one_to_one">Conversation</string>
+
+    <!-- Conversation Title fallback if the there is no name provided in a group chat conversation [CHAR LIMIT=40]-->
+    <string name="conversation_title_fallback_group_chat">Group Conversation</string>
+
     <!-- ResolverActivity - profile tabs -->
     <!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
     <string name="resolver_personal_tab">Personal</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 966f495..64768cf 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -146,7 +146,7 @@
         <item name="textAppearance">@style/TextAppearance.DeviceDefault.Notification</item>
     </style>
     <style name="Widget.DeviceDefault.Notification.MessagingName" parent="Widget.Material.Notification.MessagingName">
-        <item name="textAppearance">@style/TextAppearance.DeviceDefault.Notification.MessagingName</item>
+        <item name="textAppearance">@style/TextAppearance.DeviceDefault.Notification.Title</item>
     </style>
     <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Material.PreferenceFrameLayout"/>
     <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Material.ProgressBar.Inverse"/>
@@ -290,9 +290,6 @@
     <style name="TextAppearance.DeviceDefault.Notification.Title" parent="TextAppearance.Material.Notification.Title">
         <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
     </style>
-    <style name="TextAppearance.DeviceDefault.Notification.MessagingName" parent="TextAppearance.DeviceDefault.Notification.Title">
-        <item name="textSize">16sp</item>
-    </style>
     <style name="TextAppearance.DeviceDefault.Notification.Reply" parent="TextAppearance.Material.Notification.Reply">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
     </style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 63ac0e6..2415837 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -504,7 +504,7 @@
     <style name="Widget.Material.Notification.MessagingText" parent="Widget.Material.Notification.Text">
         <item name="layout_width">wrap_content</item>
         <item name="layout_height">wrap_content</item>
-        <item name="ellipsize">end</item>z
+        <item name="ellipsize">end</item>
     </style>
 
     <style name="Widget.Material.Notification.MessagingName" parent="Widget.Material.Light.TextView">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a9008d7..4c0dd8d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3615,6 +3615,7 @@
   <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" />
   <java-symbol type="integer" name="config_dynamicPowerSavingsDefaultDisableThreshold" />
   <java-symbol type="string" name="config_batterySaverScheduleProvider" />
+  <java-symbol type="string" name="config_powerSaveModeChangedListenerPackage" />
 
   <!-- For car devices -->
   <java-symbol type="string" name="car_loading_profile" />
@@ -3876,6 +3877,34 @@
   <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" />
   <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" />
 
+  <java-symbol type="string" name="conversation_single_line_name_display" />
+  <java-symbol type="string" name="conversation_title_fallback_one_to_one" />
+  <java-symbol type="string" name="conversation_title_fallback_group_chat" />
+  <java-symbol type="id" name="conversation_icon" />
+  <java-symbol type="id" name="conversation_icon_badge" />
+  <java-symbol type="id" name="expand_button_container" />
+  <java-symbol type="id" name="messaging_group_content_container" />
+  <java-symbol type="id" name="expand_button_and_content_container" />
+  <java-symbol type="id" name="conversation_header" />
+  <java-symbol type="id" name="conversation_face_pile_bottom_background" />
+  <java-symbol type="id" name="conversation_face_pile_bottom" />
+  <java-symbol type="id" name="conversation_face_pile_top" />
+  <java-symbol type="id" name="conversation_face_pile" />
+  <java-symbol type="id" name="conversation_text" />
+  <java-symbol type="id" name="message_icon_container" />
+  <java-symbol type="dimen" name="conversation_expand_button_top_margin_expanded" />
+  <java-symbol type="dimen" name="conversation_expand_button_expanded_size" />
+  <java-symbol type="dimen" name="messaging_group_singleline_sender_padding_end" />
+  <java-symbol type="dimen" name="conversation_badge_side_margin" />
+  <java-symbol type="dimen" name="conversation_icon_size_badged" />
+  <java-symbol type="dimen" name="conversation_icon_size_centered" />
+  <java-symbol type="dimen" name="conversation_icon_margin_top_centered" />
+  <java-symbol type="dimen" name="conversation_content_start" />
+  <java-symbol type="dimen" name="messaging_layout_margin_end" />
+  <java-symbol type="dimen" name="conversation_header_expanded_padding_end" />
+  <java-symbol type="layout" name="notification_template_material_conversation" />
+  <java-symbol type="layout" name="conversation_face_pile_layout" />
+
   <!-- Intent resolver and share sheet -->
   <java-symbol type="color" name="resolver_tabs_active_color" />
   <java-symbol type="color" name="resolver_tabs_inactive_color" />
diff --git a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
index 44f6407..37b2817 100644
--- a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
+++ b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
@@ -37,6 +37,8 @@
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -129,6 +131,48 @@
         assertNull(result.getCertificate());
     }
 
+    @Test
+    public void testSourceStamp_multiApk_validStamps() throws Exception {
+        File testApk1 = getApk("SourceStampVerifierTest/valid-stamp.apk");
+        File testApk2 = getApk("SourceStampVerifierTest/valid-stamp.apk");
+        ZipFile apkZipFile = new ZipFile(testApk1);
+        ZipEntry stampCertZipEntry = apkZipFile.getEntry("stamp-cert-sha256");
+        int size = (int) stampCertZipEntry.getSize();
+        byte[] expectedStampCertHash = new byte[size];
+        try (InputStream inputStream = apkZipFile.getInputStream(stampCertZipEntry)) {
+            inputStream.read(expectedStampCertHash);
+        }
+        List<String> apkFiles = new ArrayList<>();
+        apkFiles.add(testApk1.getAbsolutePath());
+        apkFiles.add(testApk2.getAbsolutePath());
+
+        SourceStampVerificationResult result =
+                SourceStampVerifier.verify(apkFiles);
+
+        assertTrue(result.isPresent());
+        assertTrue(result.isVerified());
+        assertNotNull(result.getCertificate());
+        byte[] actualStampCertHash =
+                MessageDigest.getInstance("SHA-256").digest(result.getCertificate().getEncoded());
+        assertArrayEquals(expectedStampCertHash, actualStampCertHash);
+    }
+
+    @Test
+    public void testSourceStamp_multiApk_invalidStamps() throws Exception {
+        File testApk1 = getApk("SourceStampVerifierTest/valid-stamp.apk");
+        File testApk2 = getApk("SourceStampVerifierTest/stamp-apk-hash-mismatch.apk");
+        List<String> apkFiles = new ArrayList<>();
+        apkFiles.add(testApk1.getAbsolutePath());
+        apkFiles.add(testApk2.getAbsolutePath());
+
+        SourceStampVerificationResult result =
+                SourceStampVerifier.verify(apkFiles);
+
+        assertTrue(result.isPresent());
+        assertFalse(result.isVerified());
+        assertNull(result.getCertificate());
+    }
+
     private File getApk(String apkPath) throws IOException {
         File testApk = File.createTempFile("SourceStampApk", ".apk");
         try (InputStream inputStream = mContext.getAssets().open(apkPath)) {
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 50cd5a3..fe25e79 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -123,7 +123,7 @@
         mController = new InsetsAnimationControlImpl(controls,
                 new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
                 mMockController, 10 /* durationMs */, new LinearInterpolator(),
-                false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN, 0 /* animationType */);
+                false /* fade */, 0 /* animationType */);
     }
 
     @Test
@@ -182,7 +182,7 @@
 
     @Test
     public void testCancelled() {
-        mController.onCancelled();
+        mController.cancel();
         try {
             mController.setInsetsAndAlpha(Insets.NONE, 1f /*alpha */, 0f /* fraction */);
             fail("Expected exception to be thrown");
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 023fc17..42ab2e7 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -31,6 +31,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -47,6 +48,7 @@
 import android.graphics.Rect;
 import android.os.CancellationSignal;
 import android.platform.test.annotations.Presubmit;
+import android.view.InsetsState.InternalInsetsType;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
@@ -56,12 +58,12 @@
 import android.view.test.InsetsModeSession;
 import android.widget.TextView;
 
-import com.android.server.testutils.OffsettableClock;
-import com.android.server.testutils.TestHandler;
-
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
+
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -72,7 +74,6 @@
 import org.mockito.Mockito;
 
 import java.util.concurrent.CountDownLatch;
-import java.util.function.Supplier;
 
 /**
  * Tests for {@link InsetsController}.
@@ -169,11 +170,8 @@
 
     @Test
     public void testControlsChanged() {
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
-        mController.onControlsChanged(new InsetsSourceControl[] { control });
-        assertEquals(mLeash,
-                mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
+        mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
+        assertNotNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
         mController.addOnControllableInsetsChangedListener(
                 ((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
     }
@@ -183,9 +181,7 @@
         OnControllableInsetsChangedListener listener
                 = mock(OnControllableInsetsChangedListener.class);
         mController.addOnControllableInsetsChangedListener(listener);
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
-        mController.onControlsChanged(new InsetsSourceControl[] { control });
+        mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
         mController.onControlsChanged(new InsetsSourceControl[0]);
         assertNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl());
         InOrder inOrder = Mockito.inOrder(listener);
@@ -197,14 +193,12 @@
     @Test
     public void testControlsRevoked_duringAnim() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            InsetsSourceControl control =
-                    new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
-            mController.onControlsChanged(new InsetsSourceControl[] { control });
+            mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
 
             WindowInsetsAnimationControlListener mockListener =
                     mock(WindowInsetsAnimationControlListener.class);
             mController.controlWindowInsetsAnimation(statusBars(), 10 /* durationMs */,
-                    new LinearInterpolator(), mockListener);
+                    new LinearInterpolator(), new CancellationSignal(), mockListener);
 
             // Ready gets deferred until next predraw
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -224,7 +218,7 @@
         WindowInsetsAnimationControlListener controlListener =
                 mock(WindowInsetsAnimationControlListener.class);
         mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, new LinearInterpolator(),
-                controlListener);
+                new CancellationSignal(), controlListener);
         mController.addOnControllableInsetsChangedListener(
                 (controller, typeMask) -> assertEquals(0, typeMask));
         verify(controlListener).onCancelled();
@@ -262,11 +256,8 @@
 
     @Test
     public void testApplyImeVisibility() {
-        final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
-
-        InsetsSourceControl[] controls = new InsetsSourceControl[3];
-        controls[0] = ime;
-        mController.onControlsChanged(controls);
+        InsetsSourceControl ime = createControl(ITYPE_IME);
+        mController.onControlsChanged(new InsetsSourceControl[] { ime });
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
             mController.applyImeVisibility(true);
@@ -429,9 +420,7 @@
 
     @Test
     public void testRestoreStartsAnimation() {
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
-        mController.onControlsChanged(new InsetsSourceControl[]{control});
+        mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.hide(Type.statusBars());
@@ -448,7 +437,7 @@
             assertTrue(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
 
             // Gaining control
-            mController.onControlsChanged(new InsetsSourceControl[]{control});
+            mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
             assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
             mController.cancelExistingAnimation();
             assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
@@ -459,8 +448,6 @@
 
     @Test
     public void testStartImeAnimationAfterGettingControl() {
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
 
@@ -471,7 +458,7 @@
             mController.show(ime(), true /* fromIme */);
 
             // Gaining control shortly after
-            mController.onControlsChanged(new InsetsSourceControl[]{control});
+            mController.onControlsChanged(createSingletonControl(ITYPE_IME));
 
             assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
             mController.cancelExistingAnimation();
@@ -483,16 +470,13 @@
 
     @Test
     public void testStartImeAnimationAfterGettingControl_imeLater() {
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
-
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
 
             mController.show(ime());
             assertFalse(mController.getState().getSource(ITYPE_IME).isVisible());
 
             // Gaining control shortly after
-            mController.onControlsChanged(new InsetsSourceControl[]{control});
+            mController.onControlsChanged(createSingletonControl(ITYPE_IME));
 
             // Pretend IME is calling
             mController.show(ime(), true /* fromIme */);
@@ -507,15 +491,13 @@
 
     @Test
     public void testAnimationEndState_controller() throws Exception {
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
-        mController.onControlsChanged(new InsetsSourceControl[] { control });
+        mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener mockListener =
                     mock(WindowInsetsAnimationControlListener.class);
             mController.controlWindowInsetsAnimation(statusBars(), 0 /* durationMs */,
-                    new LinearInterpolator(), mockListener);
+                    new LinearInterpolator(), new CancellationSignal(), mockListener);
 
             ArgumentCaptor<WindowInsetsAnimationController> controllerCaptor =
                     ArgumentCaptor.forClass(WindowInsetsAnimationController.class);
@@ -535,16 +517,15 @@
 
     @Test
     public void testCancellation_afterGainingControl() throws Exception {
-        InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
-        mController.onControlsChanged(new InsetsSourceControl[] { control });
+        mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener mockListener =
                     mock(WindowInsetsAnimationControlListener.class);
-            CancellationSignal cancellationSignal = mController.controlWindowInsetsAnimation(
+            CancellationSignal cancellationSignal = new CancellationSignal();
+            mController.controlWindowInsetsAnimation(
                     statusBars(), 0 /* durationMs */,
-                    new LinearInterpolator(), mockListener);
+                    new LinearInterpolator(), cancellationSignal, mockListener);
 
             // Ready gets deferred until next predraw
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -567,7 +548,8 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener listener =
                     mock(WindowInsetsAnimationControlListener.class);
-            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
+            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(),
+                    null /* cancellationSignal */, listener);
 
             // Ready gets deferred until next predraw
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -591,7 +573,8 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener listener =
                     mock(WindowInsetsAnimationControlListener.class);
-            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
+            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(),
+                    null /* cancellationSignal */, listener);
 
             // Ready gets deferred until next predraw
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -611,7 +594,8 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener listener =
                     mock(WindowInsetsAnimationControlListener.class);
-            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
+            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(),
+                    null /* cancellationSignal */, listener);
 
             // Ready gets deferred until next predraw
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -632,8 +616,10 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             WindowInsetsAnimationControlListener listener =
                     mock(WindowInsetsAnimationControlListener.class);
-            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener)
-                    .cancel();
+            CancellationSignal cancellationSignal = new CancellationSignal();
+            mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(),
+                    cancellationSignal, listener);
+            cancellationSignal.cancel();
 
             verify(listener).onCancelled();
 
@@ -655,12 +641,23 @@
         latch.await();
     }
 
+    private InsetsSourceControl createControl(@InternalInsetsType int type) {
+
+        // Simulate binder behavior by copying SurfaceControl. Otherwise, InsetsController will
+        // attempt to release mLeash directly.
+        SurfaceControl copy = new SurfaceControl();
+        copy.copyFrom(mLeash);
+        return new InsetsSourceControl(type, copy, new Point());
+    }
+
+    private InsetsSourceControl[] createSingletonControl(@InternalInsetsType int type) {
+        return new InsetsSourceControl[] { createControl(type) };
+    }
+
     private InsetsSourceControl[] prepareControls() {
-        final InsetsSourceControl navBar = new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mLeash,
-                new Point());
-        final InsetsSourceControl statusBar = new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash,
-                new Point());
-        final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
+        final InsetsSourceControl navBar = createControl(ITYPE_NAVIGATION_BAR);
+        final InsetsSourceControl statusBar = createControl(ITYPE_STATUS_BAR);
+        final InsetsSourceControl ime = createControl(ITYPE_IME);
 
         InsetsSourceControl[] controls = new InsetsSourceControl[3];
         controls[0] = navBar;
diff --git a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
index 9797178..33f859e 100644
--- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
@@ -20,8 +20,9 @@
 import static android.view.WindowInsets.Type.systemBars;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
@@ -35,12 +36,12 @@
 import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
 import android.view.animation.LinearInterpolator;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import androidx.test.runner.AndroidJUnit4;
-
 /**
  * Tests for {@link PendingInsetsControllerTest}.
  *
@@ -95,10 +96,11 @@
     public void testControl() {
         WindowInsetsAnimationControlListener listener =
                 mock(WindowInsetsAnimationControlListener.class);
-        CancellationSignal signal = mPendingInsetsController.controlWindowInsetsAnimation(
-                systemBars(), 0, new LinearInterpolator(), listener);
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        mPendingInsetsController.controlWindowInsetsAnimation(
+                systemBars(), 0, new LinearInterpolator(), cancellationSignal, listener);
         verify(listener).onCancelled();
-        assertTrue(signal.isCanceled());
+        assertFalse(cancellationSignal.isCanceled());
     }
 
     @Test
@@ -106,10 +108,11 @@
         WindowInsetsAnimationControlListener listener =
                 mock(WindowInsetsAnimationControlListener.class);
         mPendingInsetsController.replayAndAttach(mReplayedController);
-        mPendingInsetsController.controlWindowInsetsAnimation(
-                systemBars(), 0L, new LinearInterpolator(), listener);
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        mPendingInsetsController.controlWindowInsetsAnimation(systemBars(), 0L,
+                new LinearInterpolator(), cancellationSignal, listener);
         verify(mReplayedController).controlWindowInsetsAnimation(eq(systemBars()), eq(0L), any(),
-                eq(listener));
+                eq(cancellationSignal), eq(listener));
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 02a88fc..5ea0718 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -20,6 +20,7 @@
 
 import static org.testng.Assert.assertThrows;
 
+import android.graphics.Insets;
 import android.view.View;
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
@@ -172,6 +173,11 @@
         }
 
         @Override
+        void internalNotifyViewInsetsChanged(Insets viewInsets) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
         public void updateContentCaptureContext(ContentCaptureContext context) {
             throw new UnsupportedOperationException("should not have been called");
         }
diff --git a/core/tests/coretests/src/android/view/textclassifier/SystemTextClassifierMetadataTest.java b/core/tests/coretests/src/android/view/textclassifier/SystemTextClassifierMetadataTest.java
new file mode 100644
index 0000000..e4cfc53
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/SystemTextClassifierMetadataTest.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 android.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemTextClassifierMetadataTest {
+
+    @Test
+    public void testInvalidPackageNameThrowsException() {
+        assertThrows(NullPointerException.class,
+                () -> new SystemTextClassifierMetadata(/* packageName= */ null, /* userId= */
+                        1, /* useDefaultTextClassifier= */ false));
+    }
+
+    @Test
+    public void testParcel() {
+        SystemTextClassifierMetadata sysTcMetadata = new SystemTextClassifierMetadata(
+                "package", /* userId= */ 1, /* useDefaultTextClassifier= */ false);
+
+        Parcel p = Parcel.obtain();
+        sysTcMetadata.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        SystemTextClassifierMetadata targetSysTcMetadata =
+                SystemTextClassifierMetadata.CREATOR.createFromParcel(p);
+
+        assertThat(targetSysTcMetadata.getUserId()).isEqualTo(sysTcMetadata.getUserId());
+        assertThat(targetSysTcMetadata.getCallingPackageName()).isEqualTo(
+                sysTcMetadata.getCallingPackageName());
+        assertThat(targetSysTcMetadata.useDefaultTextClassifier()).isEqualTo(
+                sysTcMetadata.useDefaultTextClassifier());
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index d544029..39ededa 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -17,6 +17,7 @@
 package android.view.textclassifier;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
@@ -199,7 +200,9 @@
                         .setReferenceTime(referenceTime)
                         .setExtras(BUNDLE)
                         .build();
-        reference.setCallingPackageName(packageName);
+        final SystemTextClassifierMetadata systemTcMetadata =
+                new SystemTextClassifierMetadata(packageName, 1, false);
+        reference.setSystemTextClassifierMetadata(systemTcMetadata);
 
         // Parcel and unparcel.
         final Parcel parcel = Parcel.obtain();
@@ -216,5 +219,11 @@
         assertEquals(referenceTime, result.getReferenceTime());
         assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
         assertEquals(packageName, result.getCallingPackageName());
+        final SystemTextClassifierMetadata resultSystemTcMetadata =
+                result.getSystemTextClassifierMetadata();
+        assertNotNull(resultSystemTcMetadata);
+        assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+        assertEquals(1, resultSystemTcMetadata.getUserId());
+        assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
index d0d32e3..31f8029 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -17,6 +17,8 @@
 package android.view.textclassifier;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 
 import android.icu.util.ULocale;
 import android.os.Bundle;
@@ -75,7 +77,9 @@
         final TextLanguage.Request reference = new TextLanguage.Request.Builder(text)
                 .setExtras(bundle)
                 .build();
-        reference.setCallingPackageName(packageName);
+        final SystemTextClassifierMetadata systemTcMetadata =
+                new SystemTextClassifierMetadata(packageName, 1, false);
+        reference.setSystemTextClassifierMetadata(systemTcMetadata);
 
         final Parcel parcel = Parcel.obtain();
         reference.writeToParcel(parcel, 0);
@@ -85,5 +89,11 @@
         assertEquals(text, result.getText());
         assertEquals("bundle", result.getExtras().getString(bundleKey));
         assertEquals(packageName, result.getCallingPackageName());
+        final SystemTextClassifierMetadata resultSystemTcMetadata =
+                result.getSystemTextClassifierMetadata();
+        assertNotNull(resultSystemTcMetadata);
+        assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+        assertEquals(1, resultSystemTcMetadata.getUserId());
+        assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
index ec5813f..4f0b44b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -17,6 +17,8 @@
 package android.view.textclassifier;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -115,7 +117,9 @@
                 .setExtras(BUNDLE)
                 .setReferenceTime(referenceTime)
                 .build();
-        reference.setCallingPackageName(packageName);
+        final SystemTextClassifierMetadata systemTcMetadata =
+                new SystemTextClassifierMetadata(packageName, 1, false);
+        reference.setSystemTextClassifierMetadata(systemTcMetadata);
 
         // Parcel and unparcel.
         final Parcel parcel = Parcel.obtain();
@@ -132,5 +136,11 @@
         assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
         assertEquals(packageName, result.getCallingPackageName());
         assertEquals(referenceTime, result.getReferenceTime());
+        final SystemTextClassifierMetadata resultSystemTcMetadata =
+                result.getSystemTextClassifierMetadata();
+        assertNotNull(resultSystemTcMetadata);
+        assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+        assertEquals(1, resultSystemTcMetadata.getUserId());
+        assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 30cc4e8..82788c8 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -17,6 +17,8 @@
 package android.view.textclassifier;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -82,7 +84,9 @@
                         .setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY))
                         .setExtras(BUNDLE)
                         .build();
-        reference.setCallingPackageName(packageName);
+        final SystemTextClassifierMetadata systemTcMetadata =
+                new SystemTextClassifierMetadata(packageName, 1, false);
+        reference.setSystemTextClassifierMetadata(systemTcMetadata);
 
         // Parcel and unparcel.
         final Parcel parcel = Parcel.obtain();
@@ -96,5 +100,11 @@
         assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
         assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
         assertEquals(packageName, result.getCallingPackageName());
+        final SystemTextClassifierMetadata resultSystemTcMetadata =
+                result.getSystemTextClassifierMetadata();
+        assertNotNull(resultSystemTcMetadata);
+        assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+        assertEquals(1, resultSystemTcMetadata.getUserId());
+        assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java b/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java
index 36dd3e4..03ed68c 100644
--- a/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java
@@ -98,6 +98,11 @@
 
             @Override
             void handleResultMessage(Message message) {}
+
+            @Override
+            List<ComponentName> getTopComponentNames(int topK) {
+                return null;
+            }
         };
         return testComparator;
     }
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 24e96d4..a6cbc1a 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -987,7 +987,8 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos)
+                        directShareToShortcutInfos,
+                        null)
         );
 
         // Thread.sleep shouldn't be a thing in an integration test but it's
@@ -1058,7 +1059,8 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos)
+                        directShareToShortcutInfos,
+                        null)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
@@ -1145,7 +1147,8 @@
                                 /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET,
-                        directShareToShortcutInfos)
+                        directShareToShortcutInfos,
+                        null)
         );
         // Thread.sleep shouldn't be a thing in an integration test but it's
         // necessary here because of the way the code is structured
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index 61281ee..efe658a 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -33,6 +33,7 @@
         <permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
         <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.MONITOR_INPUT"/>
         <permission name="android.permission.PROVIDE_TRUST_AGENT"/>
         <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
         <permission name="android.permission.REAL_GET_TASKS"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 487a6e9..5466ac8 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -62,6 +62,10 @@
         <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.launcher3">
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.location.fused">
         <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
         <permission name="android.permission.UPDATE_DEVICE_STATS"/>
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 550e41f..ff7049e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -612,7 +612,7 @@
     public Location getLastLocation() {
         try {
             return mService.getLastLocation(null, mContext.getPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -645,7 +645,7 @@
 
         try {
             return mService.getLastLocation(request, mContext.getPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -742,7 +742,7 @@
 
         try {
             if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal,
-                    listenerTransport, mContext.getPackageName(), mContext.getFeatureId(),
+                    listenerTransport, mContext.getPackageName(), mContext.getAttributionTag(),
                     getListenerIdentifier(consumer))) {
                 listenerTransport.register(mContext.getSystemService(AlarmManager.class),
                         remoteCancellationSignal);
@@ -1189,7 +1189,7 @@
             boolean registered = false;
             try {
                 mService.requestLocationUpdates(locationRequest, transport, null,
-                        mContext.getPackageName(), mContext.getFeatureId(),
+                        mContext.getPackageName(), mContext.getAttributionTag(),
                         getListenerIdentifier(listener));
                 registered = true;
             } catch (RemoteException e) {
@@ -1235,7 +1235,7 @@
 
         try {
             mService.requestLocationUpdates(locationRequest, null, pendingIntent,
-                    mContext.getPackageName(), mContext.getFeatureId(),
+                    mContext.getPackageName(), mContext.getAttributionTag(),
                     getListenerIdentifier(pendingIntent));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1711,7 +1711,7 @@
         LocationRequest request = new LocationRequest().setExpireIn(expiration);
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
-                    mContext.getFeatureId(), getListenerIdentifier(intent));
+                    mContext.getAttributionTag(), getListenerIdentifier(intent));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1798,7 +1798,7 @@
 
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
-                    mContext.getFeatureId(), getListenerIdentifier(intent));
+                    mContext.getAttributionTag(), getListenerIdentifier(intent));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2946,7 +2946,7 @@
 
             GnssStatusListener transport = new GnssStatusListener();
             if (mService.registerGnssStatusCallback(transport, mContext.getPackageName(),
-                    mContext.getFeatureId())) {
+                    mContext.getAttributionTag())) {
                 mListenerTransport = transport;
                 return true;
             } else {
@@ -3012,7 +3012,7 @@
 
             GnssMeasurementsListener transport = new GnssMeasurementsListener();
             if (mService.addGnssMeasurementsListener(request, transport, mContext.getPackageName(),
-                    mContext.getFeatureId(), "gnss measurement callback")) {
+                    mContext.getAttributionTag(), "gnss measurement callback")) {
                 mListenerTransport = transport;
                 return true;
             } else {
@@ -3065,7 +3065,7 @@
 
             GnssNavigationMessageListener transport = new GnssNavigationMessageListener();
             if (mService.addGnssNavigationMessageListener(transport, mContext.getPackageName(),
-                    mContext.getFeatureId(), "gnss navigation callback")) {
+                    mContext.getAttributionTag(), "gnss navigation callback")) {
                 mListenerTransport = transport;
                 return true;
             } else {
@@ -3106,7 +3106,7 @@
 
             GnssAntennaInfoListener transport = new GnssAntennaInfoListener();
             if (mService.addGnssAntennaInfoListener(transport, mContext.getPackageName(),
-                    mContext.getFeatureId(), "gnss antenna info callback")) {
+                    mContext.getAttributionTag(), "gnss antenna info callback")) {
                 mListenerTransport = transport;
                 return true;
             } else {
@@ -3143,7 +3143,7 @@
 
             BatchedLocationCallback transport = new BatchedLocationCallback();
             if (mService.addGnssBatchingCallback(transport, mContext.getPackageName(),
-                    mContext.getFeatureId(), "batched location callback")) {
+                    mContext.getAttributionTag(), "batched location callback")) {
                 mListenerTransport = transport;
                 return true;
             } else {
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 8e39dfa..fb95e98 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -466,10 +466,6 @@
             return;
         }
 
-        List<RoutingSessionInfo> sessionInfos;
-        synchronized (mSessionLock) {
-            sessionInfos = new ArrayList<>(mSessionInfo.values());
-        }
         try {
             mRemoteCallback.updateState(mProviderInfo);
         } catch (RemoteException ex) {
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 37e2ab5..80545e5 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -58,7 +58,7 @@
 // TODO: Add method names at the beginning of log messages. (e.g. updateControllerOnHandler)
 //       Not only MediaRouter2, but also to service / manager / provider.
 // TODO: ensure thread-safe and document it
-public class MediaRouter2 {
+public final class MediaRouter2 {
     private static final String TAG = "MR2";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final Object sRouterLock = new Object();
@@ -93,9 +93,9 @@
     MediaRouter2Stub mStub;
 
     @GuardedBy("sRouterLock")
-    private Map<String, RoutingController> mRoutingControllers = new ArrayMap<>();
+    private final Map<String, RoutingController> mRoutingControllers = new ArrayMap<>();
 
-    private AtomicInteger mControllerCreationRequestCnt = new AtomicInteger(1);
+    private final AtomicInteger mControllerCreationRequestCnt = new AtomicInteger(1);
 
     final Handler mHandler;
     @GuardedBy("sRouterLock")
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 11c9fe1..88bcd6a 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -50,7 +50,7 @@
  * A class that monitors and controls media routing of other apps.
  * @hide
  */
-public class MediaRouter2Manager {
+public final class MediaRouter2Manager {
     private static final String TAG = "MR2Manager";
     private static final Object sLock = new Object();
 
@@ -61,7 +61,7 @@
 
     final String mPackageName;
 
-    private Context mContext;
+    private final Context mContext;
     @GuardedBy("sLock")
     private Client mClient;
     private final IMediaRouterService mMediaRouterService;
@@ -74,7 +74,7 @@
     @NonNull
     final ConcurrentMap<String, List<String>> mPreferredFeaturesMap = new ConcurrentHashMap<>();
 
-    private AtomicInteger mNextRequestId = new AtomicInteger(1);
+    private final AtomicInteger mNextRequestId = new AtomicInteger(1);
 
     /**
      * Gets an instance of media router manager that controls media route of other applications.
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index 705d520..197c1c5 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -144,17 +144,17 @@
 
 
     private final int mModulation;
-    private final long mFec;
+    private final long mInnerFec;
     private final int mSymbolRate;
     private final int mOuterFec;
     private final int mAnnex;
     private final int mSpectralInversion;
 
-    private DvbcFrontendSettings(int frequency, int modulation, long fec, int symbolRate,
+    private DvbcFrontendSettings(int frequency, int modulation, long innerFec, int symbolRate,
             int outerFec, int annex, int spectralInversion) {
         super(frequency);
         mModulation = modulation;
-        mFec = fec;
+        mInnerFec = innerFec;
         mSymbolRate = symbolRate;
         mOuterFec = outerFec;
         mAnnex = annex;
@@ -172,8 +172,8 @@
      * Gets Inner Forward Error Correction.
      */
     @InnerFec
-    public long getFec() {
-        return mFec;
+    public long getInnerFec() {
+        return mInnerFec;
     }
     /**
      * Gets Symbol Rate in symbols per second.
@@ -220,7 +220,7 @@
      */
     public static class Builder extends FrontendSettings.Builder<Builder> {
         private int mModulation;
-        private long mFec;
+        private long mInnerFec;
         private int mSymbolRate;
         private int mOuterFec;
         private int mAnnex;
@@ -241,8 +241,8 @@
          * Sets Inner Forward Error Correction.
          */
         @NonNull
-        public Builder setFec(@InnerFec long fec) {
-            mFec = fec;
+        public Builder setInnerFec(@InnerFec long fec) {
+            mInnerFec = fec;
             return this;
         }
         /**
@@ -283,8 +283,8 @@
          */
         @NonNull
         public DvbcFrontendSettings build() {
-            return new DvbcFrontendSettings(mFrequency, mModulation, mFec, mSymbolRate, mOuterFec,
-                    mAnnex, mSpectralInversion);
+            return new DvbcFrontendSettings(mFrequency, mModulation, mInnerFec, mSymbolRate,
+                mOuterFec, mAnnex, mSpectralInversion);
         }
 
         @Override
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 63de0334..ea91ee9 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -304,7 +304,7 @@
      *  and ETSI EN 302 307-2 V1.1.1.
      */
     @FrontendSettings.InnerFec
-    public long getFec() {
+    public long getInnerFec() {
         if (mInnerFec == null) {
             throw new IllegalStateException();
         }
diff --git a/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 20efaa1..77cac6e 100644
--- a/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -19,6 +19,8 @@
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
+import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
 import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
@@ -148,6 +150,53 @@
     void shareFrontend(in int selfClientId, in int targetClientId);
 
     /*
+     * This API is used by the Tuner framework to request an available demux from the TunerHAL.
+     *
+     * <p>There are three possible scenarios:
+     * <ul>
+     * <li>If there is demux available, the API would send the handle back.
+     *
+     * <li>If no Demux is available but the current request info can show higher priority than
+     * other uses of demuxes, the API will send
+     * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would
+     * handle the resource reclaim on the holder of lower priority and notify the holder of its
+     * resource loss.
+     *
+     * <li>If no demux can be granted, the API would return false.
+     * <ul>
+     *
+     * @param request {@link TunerDemuxRequest} information of the current request.
+     * @param demuxHandle a one-element array to return the granted demux handle.
+     *
+     * @return true if there is demux granted.
+     */
+    boolean requestDemux(in TunerDemuxRequest request, out int[] demuxHandle);
+
+    /*
+     * This API is used by the Tuner framework to request an available descrambler from the
+     * TunerHAL.
+     *
+     * <p>There are three possible scenarios:
+     * <ul>
+     * <li>If there is descrambler available, the API would send the handle back.
+     *
+     * <li>If no Descrambler is available but the current request info can show higher priority than
+     * other uses of Descrambler, the API will send
+     * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would
+     * handle the resource reclaim on the holder of lower priority and notify the holder of its
+     * resource loss.
+     *
+     * <li>If no Descrambler can be granted, the API would return false.
+     * <ul>
+     *
+     * @param request {@link TunerDescramblerRequest} information of the current request.
+     * @param descramblerHandle a one-element array to return the granted descrambler handle.
+     *
+     * @return true if there is Descrambler granted.
+     */
+    boolean requestDescrambler(in TunerDescramblerRequest request, out int[] descramblerHandle);
+
+    /*
      * This API is used by the Tuner framework to request an available Cas session. This session
      * needs to be under the CAS system with the id indicated in the {@code request}.
      *
@@ -210,6 +259,24 @@
     void releaseFrontend(in int frontendId);
 
     /*
+     * Notifies the TRM that the Demux with the given handle was released.
+     *
+     * <p>Client must call this whenever it releases a demux.
+     *
+     * @param demuxHandle the handle of the released Tuner Demux.
+     */
+    void releaseDemux(in int demuxHandle);
+
+    /*
+     * Notifies the TRM that the Descrambler with the given handle was released.
+     *
+     * <p>Client must call this whenever it releases a descrambler.
+     *
+     * @param demuxHandle the handle of the released Tuner Descrambler.
+     */
+    void releaseDescrambler(in int descramblerHandle);
+
+    /*
      * Notifies the TRM that the given Cas session has been released.
      *
      * <p>Client must call this whenever it releases a Cas session.
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
new file mode 100644
index 0000000..919a215
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+/**
+ * Information required to request a Tuner Demux.
+ *
+ * @hide
+ */
+parcelable TunerDemuxRequest;
\ No newline at end of file
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.java b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.java
new file mode 100644
index 0000000..34a7761
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Information required to request a Tuner Demux.
+ *
+ * @hide
+ */
+public final class TunerDemuxRequest implements Parcelable {
+    static final String TAG = "TunerDemuxRequest";
+
+    public static final
+                @NonNull
+                Parcelable.Creator<TunerDemuxRequest> CREATOR =
+                new Parcelable.Creator<TunerDemuxRequest>() {
+                @Override
+                public TunerDemuxRequest createFromParcel(Parcel source) {
+                    try {
+                        return new TunerDemuxRequest(source);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Exception creating TunerDemuxRequest from parcel", e);
+                        return null;
+                    }
+                }
+
+                @Override
+                public TunerDemuxRequest[] newArray(int size) {
+                    return new TunerDemuxRequest[size];
+                }
+            };
+
+    /**
+     * Client id of the client that sends the request.
+     */
+    private final int mClientId;
+
+    private TunerDemuxRequest(@NonNull Parcel source) {
+        mClientId = source.readInt();
+    }
+
+    /**
+     * Constructs a new {@link TunerDemuxRequest} with the given parameters.
+     *
+     * @param clientId id of the client.
+     */
+    public TunerDemuxRequest(int clientId) {
+        mClientId = clientId;
+    }
+
+    /**
+     * Returns the id of the client.
+     */
+    public int getClientId() {
+        return mClientId;
+    }
+
+    // Parcelable
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder(128);
+        b.append("TunerDemuxRequest {clientId=").append(mClientId);
+        b.append("}");
+        return b.toString();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mClientId);
+    }
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl
new file mode 100644
index 0000000..fbafb3b
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+/**
+ * Information required to request a Tuner Descrambler.
+ *
+ * @hide
+ */
+parcelable TunerDescramblerRequest;
\ No newline at end of file
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.java b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.java
new file mode 100644
index 0000000..5816287
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Information required to request a Tuner Descrambler.
+ *
+ * @hide
+ */
+public final class TunerDescramblerRequest implements Parcelable {
+    static final String TAG = "TunerDescramblerRequest";
+
+    public static final
+                @NonNull
+                Parcelable.Creator<TunerDescramblerRequest> CREATOR =
+                new Parcelable.Creator<TunerDescramblerRequest>() {
+                @Override
+                public TunerDescramblerRequest createFromParcel(Parcel source) {
+                    try {
+                        return new TunerDescramblerRequest(source);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Exception creating TunerDescramblerRequest from parcel", e);
+                        return null;
+                    }
+                }
+
+                @Override
+                public TunerDescramblerRequest[] newArray(int size) {
+                    return new TunerDescramblerRequest[size];
+                }
+            };
+
+    /**
+     * Client id of the client that sends the request.
+     */
+    private final int mClientId;
+
+    private TunerDescramblerRequest(@NonNull Parcel source) {
+        mClientId = source.readInt();
+    }
+
+    /**
+     * Constructs a new {@link TunerDescramblerRequest} with the given parameters.
+     *
+     * @param clientId id of the client.
+     */
+    public TunerDescramblerRequest(int clientId) {
+        mClientId = clientId;
+    }
+
+    /**
+     * Returns the id of the client.
+     */
+    public int getClientId() {
+        return mClientId;
+    }
+
+    // Parcelable
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder(128);
+        b.append("TunerDescramblerRequest {clientId=").append(mClientId);
+        b.append("}");
+        return b.toString();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mClientId);
+    }
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 7c11ed4..9dddcd4 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -60,11 +60,7 @@
     private static final String TAG = "TunerResourceManager";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final int INVALID_FRONTEND_ID = -1;
-    public static final int INVALID_CAS_SESSION_RESOURCE_ID = -1;
-    public static final int INVALID_LNB_ID = -1;
-    public static final int INVALID_TV_INPUT_DEVICE_ID = -1;
-    public static final int INVALID_TV_INPUT_PORT_ID = -1;
+    public static final int INVALID_RESOURCE_HANDLE = -1;
 
     private final ITunerResourceManager mService;
     private final int mUserId;
@@ -260,6 +256,71 @@
     }
 
     /**
+     * Requests a Tuner Demux resource.
+     *
+     * <p>There are three possible scenarios:
+     * <ul>
+     * <li>If there is Demux available, the API would send the handle back.
+     *
+     * <li>If no Demux is available but the current request has a higher priority than other uses of
+     * demuxes, the API will send {@link IResourcesReclaimListener#onReclaimResources()} to the
+     * {@link Tuner}. Tuner would handle the resource reclaim on the holder of lower priority and
+     * notify the holder of its resource loss.
+     *
+     * <li>If no Demux system can be granted, the API would return false.
+     * <ul>
+     *
+     * @param request {@link TunerDemuxRequest} information of the current request.
+     * @param demuxHandle a one-element array to return the granted Demux handle.
+     *                    If no Demux granted, this will return {@link #INVALID_RESOURCE_HANDLE}.
+     *
+     * @return true if there is Demux granted.
+     */
+    public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull int[] demuxHandle) {
+        boolean result = false;
+        try {
+            result = mService.requestDemux(request, demuxHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return result;
+    }
+
+    /**
+     * Requests a Tuner Descrambler resource.
+     *
+     * <p>There are three possible scenarios:
+     * <ul>
+     * <li>If there is Descrambler available, the API would send the handle back.
+     *
+     * <li>If no Descrambler is available but the current request has a higher priority than other
+     * uses of descramblers, the API will send
+     * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would
+     * handle the resource reclaim on the holder of lower priority and notify the holder of its
+     * resource loss.
+     *
+     * <li>If no Descrambler system can be granted, the API would return false.
+     * <ul>
+     *
+     * @param request {@link TunerDescramblerRequest} information of the current request.
+     * @param descramblerHandle a one-element array to return the granted Descrambler handle.
+     *                          If no Descrambler granted, this will return
+     *                          {@link #INVALID_RESOURCE_HANDLE}.
+     *
+     * @return true if there is Descrambler granted.
+     */
+    public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
+                @NonNull int[] descramblerHandle) {
+        boolean result = false;
+        try {
+            result = mService.requestDescrambler(request, descramblerHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return result;
+    }
+
+    /**
      * Requests a CAS session resource.
      *
      * <p>There are three possible scenarios:
@@ -345,6 +406,36 @@
     }
 
     /**
+     * Notifies the TRM that the Demux with the given handle has been released.
+     *
+     * <p>Client must call this whenever it releases an Demux.
+     *
+     * @param demuxHandle the handle of the released Tuner Demux.
+     */
+    public void releaseDemux(int demuxHandle) {
+        try {
+            mService.releaseDemux(demuxHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Notifies the TRM that the Descrambler with the given handle has been released.
+     *
+     * <p>Client must call this whenever it releases an Descrambler.
+     *
+     * @param descramblerHandle the handle of the released Tuner Descrambler.
+     */
+    public void releaseDescrambler(int descramblerHandle) {
+        try {
+            mService.releaseDescrambler(descramblerHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Notifies the TRM that the given Cas session has been released.
      *
      * <p>Client must call this whenever it releases a Cas session.
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 6354ccd..ebd7658 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -284,12 +284,12 @@
             ICameraDeviceCallbacks dummyCallbacks = new DummyCameraDeviceCallbacks();
 
             String clientPackageName = getContext().getPackageName();
-            String clientFeatureId = getContext().getFeatureId();
+            String clientAttributionTag = getContext().getAttributionTag();
 
             ICameraDeviceUser cameraUser =
                     mUtils.getCameraService().connectDevice(
                         dummyCallbacks, String.valueOf(cameraId),
-                        clientPackageName, clientFeatureId,
+                        clientPackageName, clientAttributionTag,
                         ICameraService.USE_CALLING_UID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 466c5f4..bf3e746 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -238,12 +238,12 @@
         ICameraDeviceCallbacks.Stub dummyCallbacks = new DummyCameraDeviceCallbacks();
 
         String clientPackageName = getContext().getPackageName();
-        String clientFeatureId = getContext().getFeatureId();
+        String clientAttributionTag = getContext().getAttributionTag();
 
         mMockCb = spy(dummyCallbacks);
 
         mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
-                clientPackageName, clientFeatureId, ICameraService.USE_CALLING_UID);
+                clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID);
         assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
diff --git a/media/tests/MediaRouter/AndroidManifest.xml b/media/tests/MediaRouter/AndroidManifest.xml
index 9546500..d9806f3 100644
--- a/media/tests/MediaRouter/AndroidManifest.xml
+++ b/media/tests/MediaRouter/AndroidManifest.xml
@@ -19,7 +19,7 @@
 
     <application android:label="@string/app_name">
         <uses-library android:name="android.test.runner" />
-        <service android:name=".SampleMediaRoute2ProviderService"
+        <service android:name=".StubMediaRoute2ProviderService"
                  android:exported="true">
             <intent-filter>
                 <action android:name="android.media.MediaRoute2ProviderService" />
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 230b9e4..a97baaf 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -22,16 +22,16 @@
 import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
 import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
 
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SAMPLE;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SPECIAL;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID1;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID2;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_NAME2;
-import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.VOLUME_MAX;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID1;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID2;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_NAME2;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.VOLUME_MAX;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -115,7 +115,7 @@
         // unregister callbacks
         clearCallbacks();
 
-        SampleMediaRoute2ProviderService instance = SampleMediaRoute2ProviderService.getInstance();
+        StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
         if (instance != null) {
             instance.setProxy(null);
         }
@@ -161,8 +161,8 @@
 
         MediaRoute2Info routeToRemove = routes.get(ROUTE_ID2);
 
-        SampleMediaRoute2ProviderService sInstance =
-                SampleMediaRoute2ProviderService.getInstance();
+        StubMediaRoute2ProviderService sInstance =
+                StubMediaRoute2ProviderService.getInstance();
         assertNotNull(sInstance);
         sInstance.removeRoute(ROUTE_ID2);
         assertTrue(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
@@ -413,12 +413,12 @@
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
 
-        SampleMediaRoute2ProviderService instance = SampleMediaRoute2ProviderService.getInstance();
+        StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
         assertNotNull(instance);
 
         final List<Long> requestIds = new ArrayList<>();
         final CountDownLatch onSetRouteVolumeLatch = new CountDownLatch(1);
-        instance.setProxy(new SampleMediaRoute2ProviderService.Proxy() {
+        instance.setProxy(new StubMediaRoute2ProviderService.Proxy() {
             @Override
             public void onSetRouteVolume(String routeId, int volume, long requestId) {
                 requestIds.add(requestId);
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
similarity index 98%
rename from media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
rename to media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
index f05d8ad..6d46ba5 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
@@ -36,7 +36,7 @@
 
 import javax.annotation.concurrent.GuardedBy;
 
-public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService {
+public class StubMediaRoute2ProviderService extends MediaRoute2ProviderService {
     private static final String TAG = "SampleMR2ProviderSvc";
     private static final Object sLock = new Object();
 
@@ -74,7 +74,7 @@
     private int mNextSessionId = 1000;
 
     @GuardedBy("sLock")
-    private static SampleMediaRoute2ProviderService sInstance;
+    private static StubMediaRoute2ProviderService sInstance;
     private Proxy mProxy;
 
     private void initializeRoutes() {
@@ -127,7 +127,7 @@
         mRoutes.put(variableVolumeRoute.getId(), variableVolumeRoute);
     }
 
-    public static SampleMediaRoute2ProviderService getInstance() {
+    public static StubMediaRoute2ProviderService getInstance() {
         synchronized (sLock) {
             return sInstance;
         }
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index f93faeb..ace50f3 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -545,7 +545,7 @@
             bundle.putString(META_DATA_PREFERENCE_KEYHINT, key);
         }
         try {
-            return provider.call(context.getPackageName(), context.getFeatureId(),
+            return provider.call(context.getPackageName(), context.getAttributionTag(),
                     uri.getAuthority(), method, uri.toString(), bundle);
         } catch (RemoteException e) {
             return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 18eb187..3c78560 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -218,7 +218,7 @@
     }
 
     public boolean supportsHighQualityAudio(BluetoothDevice device) {
-        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
         if (bluetoothDevice == null) {
             return false;
         }
@@ -227,7 +227,7 @@
     }
 
     public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
-        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
         if (bluetoothDevice == null) {
             return false;
         }
@@ -253,7 +253,7 @@
     }
 
     public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
-        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
         if (bluetoothDevice == null) {
             return;
         }
@@ -272,7 +272,7 @@
     }
 
     public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
-        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
         int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
         if (bluetoothDevice == null || !supportsHighQualityAudio(device)
                 || getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 90f55dd6..44b481d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -49,11 +49,13 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({MediaDeviceState.STATE_CONNECTED,
             MediaDeviceState.STATE_CONNECTING,
-            MediaDeviceState.STATE_DISCONNECTED})
+            MediaDeviceState.STATE_DISCONNECTED,
+            MediaDeviceState.STATE_CONNECTING_FAILED})
     public @interface MediaDeviceState {
-        int STATE_CONNECTED = 1;
-        int STATE_CONNECTING = 2;
-        int STATE_DISCONNECTED = 3;
+        int STATE_CONNECTED = 0;
+        int STATE_CONNECTING = 1;
+        int STATE_DISCONNECTED = 2;
+        int STATE_CONNECTING_FAILED = 3;
     }
 
     private final Collection<DeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
@@ -108,14 +110,12 @@
                 new InfoMediaManager(context, packageName, notification, mLocalBluetoothManager);
     }
 
-    @VisibleForTesting
-    LocalMediaManager(Context context, LocalBluetoothManager localBluetoothManager,
+    public LocalMediaManager(Context context, LocalBluetoothManager localBluetoothManager,
             InfoMediaManager infoMediaManager, String packageName) {
         mContext = context;
         mLocalBluetoothManager = localBluetoothManager;
         mInfoMediaManager = infoMediaManager;
         mPackageName = packageName;
-
     }
 
     /**
@@ -128,6 +128,7 @@
             final CachedBluetoothDevice cachedDevice =
                     ((BluetoothMediaDevice) device).getCachedDevice();
             if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
+                device.setState(MediaDeviceState.STATE_CONNECTING);
                 cachedDevice.connect();
                 return;
             }
@@ -142,6 +143,7 @@
             mCurrentConnectedDevice.disconnect();
         }
 
+        device.setState(MediaDeviceState.STATE_CONNECTING);
         if (TextUtils.isEmpty(mPackageName)) {
             mInfoMediaManager.connectDeviceWithoutPackageName(device);
         } else {
@@ -423,6 +425,7 @@
             MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
             connectDevice = connectDevice != null
                     ? connectDevice : updateCurrentConnectedDevice();
+            connectDevice.setState(MediaDeviceState.STATE_CONNECTED);
 
             if (connectDevice == mCurrentConnectedDevice) {
                 Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
@@ -440,6 +443,11 @@
 
         @Override
         public void onRequestFailed(int reason) {
+            for (MediaDevice device : mMediaDevices) {
+                if (device.getState() == MediaDeviceState.STATE_CONNECTING) {
+                    device.setState(MediaDeviceState.STATE_CONNECTING_FAILED);
+                }
+            }
             dispatchOnRequestFailed(reason);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 33c3d7e..39e6a12 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -51,6 +51,7 @@
     int mType;
 
     private int mConnectedRecord;
+    private int mState;
 
     protected final Context mContext;
     protected final MediaRoute2Info mRouteInfo;
@@ -200,6 +201,22 @@
     }
 
     /**
+     * Set current device's state
+     */
+    public void setState(@LocalMediaManager.MediaDeviceState int state) {
+        mState = state;
+    }
+
+    /**
+     * Get current device's state
+     *
+     * @return state of device
+     */
+    public @LocalMediaManager.MediaDeviceState int getState() {
+        return mState;
+    }
+
+    /**
      * Rules:
      * 1. If there is one of the connected devices identified as a carkit, this carkit will
      * be always on the top of the device list. Rule 2 and Rule 3 can’t overrule this rule.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index 68a3729..245b7843 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -8,7 +8,6 @@
 
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.OpFeatureEntry;
 import android.app.AppOpsManager.PackageOps;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -163,6 +162,6 @@
             AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, -1, null));
 
         return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
-                new OpFeatureEntry(op, false, accessEvents, null)));
+                new AppOpsManager.AttributedOpEntry(op, false, accessEvents, null)));
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 3f8d758..cc9b931 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -7,7 +7,7 @@
 
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.OpFeatureEntry;
+import android.app.AppOpsManager.AttributedOpEntry;
 import android.app.AppOpsManager.PackageOps;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -18,8 +18,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.LongSparseArray;
-import android.util.LongSparseLongArray;
-import android.util.Pair;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -164,6 +162,6 @@
                 AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, duration, null));
 
         return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
-                new OpFeatureEntry(op, false, accessEvents, null)));
+                new AttributedOpEntry(op, false, accessEvents, null)));
     }
 }
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 18d8f14..f825ec5 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
@@ -16,6 +16,8 @@
 
 package com.android.settingslib.media;
 
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -27,6 +29,8 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -53,10 +57,13 @@
 @Config(shadows = {ShadowBluetoothAdapter.class})
 public class LocalMediaManagerTest {
 
+    private static final String TEST_DEVICE_NAME_1 = "device_name_1";
+    private static final String TEST_DEVICE_NAME_2 = "device_name_2";
     private static final String TEST_DEVICE_ID_1 = "device_id_1";
     private static final String TEST_DEVICE_ID_2 = "device_id_2";
     private static final String TEST_DEVICE_ID_3 = "device_id_3";
     private static final String TEST_CURRENT_DEVICE_ID = "currentDevice_id";
+    private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
 
     @Mock
     private BluetoothMediaManager mBluetoothMediaManager;
@@ -72,10 +79,18 @@
     private A2dpProfile mA2dpProfile;
     @Mock
     private LocalBluetoothProfileManager mLocalProfileManager;
+    @Mock
+    private MediaRouter2Manager mMediaRouter2Manager;
+    @Mock
+    private MediaRoute2Info mRouteInfo1;
+    @Mock
+    private MediaRoute2Info mRouteInfo2;
 
     private Context mContext;
     private LocalMediaManager mLocalMediaManager;
     private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+    private InfoMediaDevice mInfoMediaDevice1;
+    private InfoMediaDevice mInfoMediaDevice2;
 
     @Before
     public void setUp() {
@@ -84,11 +99,18 @@
         final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
         mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(bluetoothDevices);
-
+        when(mRouteInfo1.getName()).thenReturn(TEST_DEVICE_NAME_1);
+        when(mRouteInfo1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(mRouteInfo2.getName()).thenReturn(TEST_DEVICE_NAME_2);
+        when(mRouteInfo2.getId()).thenReturn(TEST_DEVICE_ID_2);
         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
         when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
         when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
 
+        mInfoMediaDevice1 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
+                TEST_PACKAGE_NAME);
+        mInfoMediaDevice2 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo2,
+                TEST_PACKAGE_NAME);
         mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
                 mInfoMediaManager, "com.test.packagename");
         mLocalMediaManager.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -123,6 +145,32 @@
     }
 
     @Test
+    public void connectDevice_deviceNotEqualCurrentConnectedDevice_isConnectingState() {
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice1);
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice2);
+        mLocalMediaManager.mCurrentConnectedDevice = mInfoMediaDevice1;
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.connectDevice(mInfoMediaDevice2);
+
+        assertThat(mInfoMediaDevice2.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTING);
+    }
+
+    @Test
+    public void connectDevice_deviceEqualCurrentConnectedDevice_notConnectingState() {
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice1);
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice2);
+        mLocalMediaManager.mCurrentConnectedDevice = mInfoMediaDevice1;
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.connectDevice(mInfoMediaDevice1);
+
+        assertThat(mInfoMediaDevice1.getState()).isNotEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTING);
+    }
+
+    @Test
     public void connectDevice_bluetoothDeviceNotConnected_connectBluetoothDevice() {
         final MediaDevice device = mock(BluetoothMediaDevice.class);
         final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
@@ -388,6 +436,21 @@
     }
 
     @Test
+    public void onConnectedDeviceChanged_isConnectedState() {
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice1);
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice2);
+        mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
+
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_DISCONNECTED);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_1);
+
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTED);
+    }
+
+    @Test
     public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
         mLocalMediaManager.registerCallback(mCallback);
 
@@ -397,6 +460,26 @@
     }
 
     @Test
+    public void onRequestFailed_checkDevicesState() {
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice1);
+        mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice2);
+        mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
+        mInfoMediaDevice2.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
+
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTING);
+        assertThat(mInfoMediaDevice2.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTED);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onRequestFailed(REASON_UNKNOWN_ERROR);
+
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTING_FAILED);
+        assertThat(mInfoMediaDevice2.getState()).isEqualTo(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTED);
+    }
+
+    @Test
     public void getActiveMediaDevice_checkList() {
         final List<MediaDevice> devices = new ArrayList<>();
         final MediaDevice device1 = mock(MediaDevice.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 3f29b72..4b08387 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -448,4 +448,23 @@
         assertThat(mInfoMediaDevice1.getClientAppLabel()).isEqualTo(
                 mContext.getResources().getString(R.string.unknown));
     }
+
+    @Test
+    public void setState_verifyGetState() {
+        mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(
+                LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
+
+        mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(
+                LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
+
+        mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(
+                LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
+
+        mInfoMediaDevice1.setState(LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
+        assertThat(mInfoMediaDevice1.getState()).isEqualTo(
+                LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
+    }
 }
diff --git a/packages/SystemUI/res/color/control_background.xml b/packages/SystemUI/res/color/control_background.xml
deleted file mode 100644
index 977310c..0000000
--- a/packages/SystemUI/res/color/control_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:state_enabled="false"
-        android:color="@color/control_default_background" />
-  <item android:color="@color/GM2_blue_200"
-        android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/color/light_background.xml b/packages/SystemUI/res/color/light_background.xml
deleted file mode 100644
index 1299464..0000000
--- a/packages/SystemUI/res/color/light_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:state_enabled="false"
-        android:color="@color/control_default_background" />
-  <item android:color="@color/GM2_yellow_200"
-        android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/color/thermo_cool_background.xml b/packages/SystemUI/res/color/thermo_cool_background.xml
deleted file mode 100644
index 977310c..0000000
--- a/packages/SystemUI/res/color/thermo_cool_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:state_enabled="false"
-        android:color="@color/control_default_background" />
-  <item android:color="@color/GM2_blue_200"
-        android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/color/thermo_heat_background.xml b/packages/SystemUI/res/color/thermo_heat_background.xml
deleted file mode 100644
index 2709ebe..0000000
--- a/packages/SystemUI/res/color/thermo_heat_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:state_enabled="false"
-        android:color="@color/control_default_background" />
-  <item android:color="@color/GM2_red_200"
-        android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml b/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml
index 64b57c5..3acebc1 100644
--- a/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml
+++ b/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml
@@ -14,10 +14,11 @@
 limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:height="52dp"
-    android:width="52dp">
-    <path android:fillColor="#1A73E8"
-          android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
-</vector>
\ No newline at end of file
+  android:viewportWidth="24"
+  android:viewportHeight="24"
+  android:width="24dp"
+  android:height="24dp">
+  <path
+      android:fillColor="#1A73E8"
+      android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 374e3b1..c58f572 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -21,8 +21,9 @@
     android:layout_weight="1"
     android:layout_height="@dimen/control_height"
     android:padding="@dimen/control_padding"
-    android:clickable="true"
+    android:clickable="false"
     android:focusable="true"
+    android:screenReaderFocusable="true"
     android:layout_marginLeft="@dimen/control_base_item_margin"
     android:layout_marginRight="@dimen/control_base_item_margin"
     android:background="@drawable/control_background">
@@ -32,6 +33,8 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:paddingTop="@dimen/control_padding_adjustment"
+        android:clickable="false"
+        android:focusable="false"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
@@ -42,6 +45,8 @@
         android:textAppearance="@style/TextAppearance.Control.Status"
         android:paddingTop="@dimen/control_padding_adjustment"
         android:paddingStart="@dimen/control_status_padding"
+        android:clickable="false"
+        android:focusable="false"
         app:layout_constraintBottom_toBottomOf="@+id/icon"
         app:layout_constraintStart_toEndOf="@+id/icon" />
 
@@ -52,6 +57,8 @@
         android:textAppearance="@style/TextAppearance.Control.Status"
         android:paddingTop="@dimen/control_padding_adjustment"
         android:paddingStart="@dimen/control_status_padding"
+        android:clickable="false"
+        android:focusable="false"
         app:layout_constraintBottom_toBottomOf="@+id/icon"
         app:layout_constraintStart_toEndOf="@+id/status" />
 
@@ -62,6 +69,8 @@
         android:textAppearance="@style/TextAppearance.Control.Title"
         android:paddingLeft="@dimen/control_padding_adjustment"
         android:paddingRight="@dimen/control_padding_adjustment"
+        android:clickable="false"
+        android:focusable="false"
         app:layout_constraintBottom_toTopOf="@+id/subtitle"
         app:layout_constraintStart_toStartOf="parent" />
 
@@ -73,6 +82,8 @@
         android:paddingLeft="@dimen/control_padding_adjustment"
         android:paddingRight="@dimen/control_padding_adjustment"
         android:paddingBottom="@dimen/control_padding_adjustment"
+        android:clickable="false"
+        android:focusable="false"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"/>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 80c1ac8..56e2b06 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -225,4 +225,8 @@
     <color name="control_default_background">@color/GM2_grey_900</color>
     <color name="control_list_popup_background">@*android:color/background_floating_material_dark</color>
     <color name="control_spinner_dropdown">@*android:color/foreground_material_dark</color>
+    <color name="control_enabled_light_background">@color/GM2_yellow_200</color>
+    <color name="control_enabled_thermo_heat_background">@color/GM2_red_200</color>
+    <color name="control_enabled_thermo_cool_background">@color/GM2_blue_200</color>
+    <color name="control_enabled_default_background">@color/GM2_blue_200</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 20cafd0..82224df 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -468,12 +468,18 @@
     <!-- On debuggable builds, alert the user if SystemUI PSS goes over this number (in kb) -->
     <integer name="watch_heap_limit">256000</integer>
 
+    <!-- Animation duration for resizing of PIP when entering/exiting. -->
+    <integer name="config_pipResizeAnimationDuration">425</integer>
+
     <!-- Allow dragging the PIP to a location to close it -->
     <bool name="config_pipEnableDismissDragToEdge">true</bool>
 
     <!-- Allow PIP to resize to a slightly bigger state upon touch/showing the menu -->
     <bool name="config_pipEnableResizeForMenu">true</bool>
 
+    <!-- Allow PIP to enable round corner, see also R.dimen.pip_corner_radius -->
+    <bool name="config_pipEnableRoundCorner">false</bool>
+
     <!-- SystemUI Plugins that can be loaded on user builds. -->
     <string-array name="config_pluginWhitelist" translatable="false">
         <item>com.android.systemui</item>
@@ -523,4 +529,7 @@
     <!--  Flag to turn on the rendering of the above path or not  -->
     <bool name="config_enableDisplayCutoutProtection">false</bool>
 
+    <!-- Respect drawable/rounded.xml intrinsic size for multiple radius corner path customization -->
+    <bool name="config_roundedCornerMultipleRadius">false</bool>
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 291db65..e45cbec 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -124,9 +124,6 @@
     <!-- Increased height of a collapsed media notification in the status bar -->
     <dimen name="notification_min_height_media">160dp</dimen>
 
-    <!-- Increased height of a collapsed messaging notification in the status bar -->
-    <dimen name="notification_min_height_messaging">118dp</dimen>
-
     <!-- Height of a small notification in the status bar which was used before android N -->
     <dimen name="notification_min_height_legacy">64dp</dimen>
 
@@ -1234,7 +1231,7 @@
     <dimen name="control_height">106dp</dimen>
     <dimen name="control_padding">12dp</dimen>
     <dimen name="control_padding_adjustment">4dp</dimen>
-    <dimen name="control_status_normal">12sp</dimen>
+    <dimen name="control_status_normal">14sp</dimen>
     <dimen name="control_status_expanded">18sp</dimen>
     <dimen name="control_base_item_margin">2dp</dimen>
     <dimen name="control_status_padding">3dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 18fec29..3543073 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2631,10 +2631,7 @@
     <string name="controls_favorite_default_title">Controls</string>
     <!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] -->
     <string name="controls_favorite_subtitle">Choose controls for quick access</string>
-    <!-- Controls management controls screen favorites header [CHAR LIMIT=50] -->
-    <string name="controls_favorite_header_favorites">Favorites</string>
-    <!-- Controls management controls screen all header [CHAR LIMIT=50] -->
-    <string name="controls_favorite_header_all">All</string>
+
     <!-- Controls management controls screen error on load message [CHAR LIMIT=60] -->
     <string name="controls_favorite_load_error">The list of all controls could not be loaded.</string>
     <!-- Controls management controls screen header for Other zone [CHAR LIMIT=60] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4770910..20b88a1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -677,7 +677,7 @@
 
     <style name="TextAppearance.Control.Status">
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
-        <item name="android:textSize">@dimen/control_text_size</item>
+        <item name="android:textSize">@dimen/control_status_normal</item>
         <item name="android:textColor">@color/control_primary_text</item>
     </style>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 4885ade..07bd3a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -78,6 +78,9 @@
     public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
     // Winscope tracing is enabled
     public static final int SYSUI_STATE_TRACING_ENABLED = 1 << 12;
+    // The Assistant gesture should be constrained. It is up to the launcher implementation to
+    // decide how to constrain it
+    public static final int SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1 << 13;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -92,7 +95,8 @@
             SYSUI_STATE_OVERVIEW_DISABLED,
             SYSUI_STATE_HOME_DISABLED,
             SYSUI_STATE_SEARCH_DISABLED,
-            SYSUI_STATE_TRACING_ENABLED
+            SYSUI_STATE_TRACING_ENABLED,
+            SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED
     })
     public @interface SystemUiStateFlags {}
 
@@ -112,6 +116,8 @@
         str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
         str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
         str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
+        str.add((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0
+                ? "asst_gesture_constrain" : "");
         return str.toString();
     }
 
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 d33c653..29100ef 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
@@ -90,7 +90,7 @@
             view.setTranslationX((surfaceControl.getWidth() - scale * viewSize.getWidth()) / 2);
             view.setTranslationY((surfaceControl.getHeight() - scale * viewSize.getHeight()) / 2);
 
-            mSurfaceControlViewHost.addView(view, layoutParams);
+            mSurfaceControlViewHost.setView(view, layoutParams);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 3cf07d1..ba8a1a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -19,9 +19,7 @@
 import static android.view.ViewRootImpl.sNewInsetsMode;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.systemBars;
-
 import static com.android.systemui.DejankUtils.whitelistIpcs;
-
 import static java.lang.Integer.max;
 
 import android.app.Activity;
@@ -30,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.ColorStateList;
+import android.graphics.Rect;
 import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.Looper;
@@ -512,8 +511,6 @@
         boolean finish = false;
         boolean strongAuth = false;
         int eventSubtype = -1;
-        mCurrentSecuritySelection = whitelistIpcs(() ->
-                mSecurityModel.getSecurityMode(targetUserId));
         if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
             finish = true;
             eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
@@ -521,8 +518,13 @@
             finish = true;
             eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
         } else if (SecurityMode.None == mCurrentSecuritySelection) {
-            finish = true; // no security required
-            eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
+            SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
+            if (SecurityMode.None == securityMode) {
+                finish = true; // no security required
+                eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
+            } else {
+                showSecurityScreen(securityMode); // switch to the alternate security view
+            }
         } else if (authenticated) {
             switch (mCurrentSecuritySelection) {
                 case Pattern:
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 537a812..a8a3cae 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -50,6 +50,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.drawable.VectorDrawable;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -126,8 +127,9 @@
     private WindowManager mWindowManager;
     private int mRotation;
     private SecureSetting mColorInversionSetting;
-    private boolean mPendingRotationChange;
     private Handler mHandler;
+    private boolean mPendingRotationChange;
+    private boolean mIsRoundedCornerMultipleRadius;
 
     private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
             new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -194,6 +196,8 @@
         mRotation = mContext.getDisplay().getRotation();
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
+        mIsRoundedCornerMultipleRadius = mContext.getResources().getBoolean(
+                R.bool.config_roundedCornerMultipleRadius);
         updateRoundedCornerRadii();
         setupDecorations();
         setupCameraListener();
@@ -572,15 +576,22 @@
                 com.android.internal.R.dimen.rounded_corner_radius_top);
         final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.rounded_corner_radius_bottom);
-
         final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault
                 || mRoundedDefaultBottom != newRoundedDefaultBottom
                 || mRoundedDefaultTop != newRoundedDefaultTop;
 
         if (roundedCornersChanged) {
-            mRoundedDefault = newRoundedDefault;
-            mRoundedDefaultTop = newRoundedDefaultTop;
-            mRoundedDefaultBottom = newRoundedDefaultBottom;
+            // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
+            // max(width, height) size of drawable/rounded.xml instead of rounded_corner_radius
+            if (mIsRoundedCornerMultipleRadius) {
+                final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
+                mRoundedDefault = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+                mRoundedDefaultTop = mRoundedDefaultBottom = mRoundedDefault;
+            } else {
+                mRoundedDefault = newRoundedDefault;
+                mRoundedDefaultTop = newRoundedDefaultTop;
+                mRoundedDefaultBottom = newRoundedDefaultBottom;
+            }
             onTuningChanged(SIZE, null);
         }
     }
@@ -631,7 +642,8 @@
     }
 
     private boolean hasRoundedCorners() {
-        return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0;
+        return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0
+                || mIsRoundedCornerMultipleRadius;
     }
 
     private boolean shouldShowRoundedCorner(@BoundsPosition int pos) {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 5077e18..cc4ee89 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -1,6 +1,9 @@
 package com.android.systemui.assist;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -43,6 +46,7 @@
 import com.android.settingslib.applications.InterestingConfigChanges;
 import com.android.systemui.R;
 import com.android.systemui.assist.ui.DefaultUiController;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -51,6 +55,8 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * Class to manage everything related to assist in SystemUI.
  */
@@ -98,6 +104,9 @@
     public static final String INVOCATION_TYPE_KEY = "invocation_type";
     protected static final String ACTION_KEY = "action";
     protected static final String SHOW_ASSIST_HANDLES_ACTION = "show_assist_handles";
+    protected static final String SET_ASSIST_GESTURE_CONSTRAINED_ACTION =
+            "set_assist_gesture_constrained";
+    protected static final String CONSTRAINED_KEY = "should_constrain";
 
     public static final int INVOCATION_TYPE_GESTURE = 1;
     public static final int INVOCATION_TYPE_ACTIVE_EDGE = 2;
@@ -120,6 +129,7 @@
     private final PhoneStateMonitor mPhoneStateMonitor;
     private final AssistHandleBehaviorController mHandleController;
     private final UiController mUiController;
+    protected final Lazy<SysUiState> mSysUiState;
 
     private AssistOrbContainer mView;
     private final DeviceProvisionedController mDeviceProvisionedController;
@@ -185,7 +195,8 @@
             CommandQueue commandQueue,
             PhoneStateMonitor phoneStateMonitor,
             OverviewProxyService overviewProxyService,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            Lazy<SysUiState> sysUiState) {
         mContext = context;
         mDeviceProvisionedController = controller;
         mCommandQueue = commandQueue;
@@ -206,6 +217,8 @@
 
         mUiController = new DefaultUiController(mContext);
 
+        mSysUiState = sysUiState;
+
         overviewProxyService.addCallback(new OverviewProxyService.OverviewProxyListener() {
             @Override
             public void onAssistantProgress(float progress) {
@@ -243,8 +256,16 @@
                         if (VERBOSE) {
                             Log.v(TAG, "UI hints received");
                         }
-                        if (SHOW_ASSIST_HANDLES_ACTION.equals(hints.getString(ACTION_KEY))) {
+
+                        String action = hints.getString(ACTION_KEY);
+                        if (SHOW_ASSIST_HANDLES_ACTION.equals(action)) {
                             requestAssistHandles();
+                        } else if (SET_ASSIST_GESTURE_CONSTRAINED_ACTION.equals(action)) {
+                            mSysUiState.get()
+                                    .setFlag(
+                                            SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
+                                            hints.getBoolean(CONSTRAINED_KEY, false))
+                                    .commitUpdate(DEFAULT_DISPLAY);
                         }
                     }
                 });
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index cbb1982..0018d33 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -99,6 +99,8 @@
 
     // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet.
     @Nullable @AuthDialogCallback.DismissedReason Integer mPendingCallbackReason;
+    // HAT received from LockSettingsService when credential is verified.
+    @Nullable byte[] mCredentialAttestation;
 
     static class Config {
         Context mContext;
@@ -109,6 +111,7 @@
         String mOpPackageName;
         int mModalityMask;
         boolean mSkipIntro;
+        long mOperationId;
     }
 
     public static class Builder {
@@ -149,6 +152,11 @@
             return this;
         }
 
+        public Builder setOperationId(long operationId) {
+            mConfig.mOperationId = operationId;
+            return this;
+        }
+
         public AuthContainerView build(int modalityMask) {
             mConfig.mModalityMask = modalityMask;
             return new AuthContainerView(mConfig, new Injector());
@@ -224,7 +232,8 @@
 
     final class CredentialCallback implements AuthCredentialView.Callback {
         @Override
-        public void onCredentialMatched() {
+        public void onCredentialMatched(byte[] attestation) {
+            mCredentialAttestation = attestation;
             animateAway(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED);
         }
     }
@@ -341,6 +350,7 @@
 
         mCredentialView.setContainerView(this);
         mCredentialView.setUserId(mConfig.mUserId);
+        mCredentialView.setOperationId(mConfig.mOperationId);
         mCredentialView.setEffectiveUserId(mEffectiveUserId);
         mCredentialView.setCredentialType(credentialType);
         mCredentialView.setCallback(mCredentialCallback);
@@ -558,7 +568,7 @@
     private void sendPendingCallbackIfNotNull() {
         Log.d(TAG, "pendingCallback: " + mPendingCallbackReason);
         if (mPendingCallbackReason != null) {
-            mConfig.mCallback.onDismissed(mPendingCallbackReason);
+            mConfig.mCallback.onDismissed(mPendingCallbackReason, mCredentialAttestation);
             mPendingCallbackReason = null;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 6149b0b..c30477c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -20,6 +20,7 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
@@ -99,7 +100,8 @@
 
                 try {
                     if (mReceiver != null) {
-                        mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                        mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
+                                null /* credentialAttestation */);
                         mReceiver = null;
                     }
                 } catch (RemoteException e) {
@@ -124,7 +126,8 @@
                         mCurrentDialog = null;
                         if (mReceiver != null) {
                             mReceiver.onDialogDismissed(
-                                    BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                                    BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
+                                    null /* credentialAttestation */);
                             mReceiver = null;
                         }
                     }
@@ -162,35 +165,42 @@
     }
 
     @Override
-    public void onDismissed(@DismissedReason int reason) {
+    public void onDismissed(@DismissedReason int reason, @Nullable byte[] credentialAttestation) {
         switch (reason) {
             case AuthDialogCallback.DISMISSED_USER_CANCELED:
-                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
+                        credentialAttestation);
                 break;
 
             case AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE:
-                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE,
+                        credentialAttestation);
                 break;
 
             case AuthDialogCallback.DISMISSED_BUTTON_POSITIVE:
-                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED);
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
+                        credentialAttestation);
                 break;
 
             case AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED:
                 sendResultAndCleanUp(
-                        BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED);
+                        BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
+                        credentialAttestation);
                 break;
 
             case AuthDialogCallback.DISMISSED_ERROR:
-                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR);
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR,
+                        credentialAttestation);
                 break;
 
             case AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER:
-                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED,
+                        credentialAttestation);
                 break;
 
             case AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED:
-                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED);
+                sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
+                        credentialAttestation);
                 break;
 
             default:
@@ -199,13 +209,14 @@
         }
     }
 
-    private void sendResultAndCleanUp(@DismissedReason int reason) {
+    private void sendResultAndCleanUp(@DismissedReason int reason,
+            @Nullable byte[] credentialAttestation) {
         if (mReceiver == null) {
             Log.e(TAG, "sendResultAndCleanUp: Receiver is null");
             return;
         }
         try {
-            mReceiver.onDialogDismissed(reason);
+            mReceiver.onDialogDismissed(reason, credentialAttestation);
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception", e);
         }
@@ -251,13 +262,15 @@
 
     @Override
     public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int biometricModality, boolean requireConfirmation, int userId, String opPackageName) {
+            int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
+            long operationId) {
         final int authenticators = Utils.getAuthenticators(bundle);
 
         if (DEBUG) {
             Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators
                     + ", biometricModality: " + biometricModality
-                    + ", requireConfirmation: " + requireConfirmation);
+                    + ", requireConfirmation: " + requireConfirmation
+                    + ", operationId: " + operationId);
         }
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = bundle;
@@ -266,6 +279,7 @@
         args.arg3 = requireConfirmation;
         args.argi2 = userId;
         args.arg4 = opPackageName;
+        args.arg5 = operationId;
 
         boolean skipAnimation = false;
         if (mCurrentDialog != null) {
@@ -354,6 +368,7 @@
         final boolean requireConfirmation = (boolean) args.arg3;
         final int userId = args.argi2;
         final String opPackageName = (String) args.arg4;
+        final long operationId = (long) args.arg5;
 
         // Create a new dialog but do not replace the current one yet.
         final AuthDialog newDialog = buildDialog(
@@ -362,7 +377,8 @@
                 userId,
                 type,
                 opPackageName,
-                skipAnimation);
+                skipAnimation,
+                operationId);
 
         if (newDialog == null) {
             Log.e(TAG, "Unsupported type: " + type);
@@ -429,7 +445,7 @@
     }
 
     protected AuthDialog buildDialog(Bundle biometricPromptBundle, boolean requireConfirmation,
-            int userId, int type, String opPackageName, boolean skipIntro) {
+            int userId, int type, String opPackageName, boolean skipIntro, long operationId) {
         return new AuthContainerView.Builder(mContext)
                 .setCallback(this)
                 .setBiometricPromptBundle(biometricPromptBundle)
@@ -437,6 +453,7 @@
                 .setUserId(userId)
                 .setOpPackageName(opPackageName)
                 .setSkipIntro(skipIntro)
+                .setOperationId(operationId)
                 .build(type);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
index 82c8a46..b986f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
@@ -103,14 +103,16 @@
                 return;
             }
 
-            mPendingLockCheck = LockPatternChecker.checkCredential(mLockPatternUtils,
-                    password, mEffectiveUserId, this::onCredentialChecked);
+            mPendingLockCheck = LockPatternChecker.verifyCredential(mLockPatternUtils,
+                    password, mOperationId, mEffectiveUserId, this::onCredentialVerified);
         }
     }
 
     @Override
-    protected void onCredentialChecked(boolean matched, int timeoutMs) {
-        super.onCredentialChecked(matched, timeoutMs);
+    protected void onCredentialVerified(byte[] attestation, int timeoutMs) {
+        super.onCredentialVerified(attestation, timeoutMs);
+
+        final boolean matched = attestation != null;
 
         if (matched) {
             mImm.hideSoftInputFromWindow(getWindowToken(), 0 /* flags */);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
index 03136a4..6d16f43 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java
@@ -61,21 +61,22 @@
 
             if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
                 // Pattern size is less than the minimum, do not count it as a failed attempt.
-                onPatternChecked(false /* matched */, 0 /* timeoutMs */);
+                onPatternVerified(null /* attestation */, 0 /* timeoutMs */);
                 return;
             }
 
             try (LockscreenCredential credential = LockscreenCredential.createPattern(pattern)) {
-                mPendingLockCheck = LockPatternChecker.checkCredential(
+                mPendingLockCheck = LockPatternChecker.verifyCredential(
                         mLockPatternUtils,
                         credential,
+                        mOperationId,
                         mEffectiveUserId,
-                        this::onPatternChecked);
+                        this::onPatternVerified);
             }
         }
 
-        private void onPatternChecked(boolean matched, int timeoutMs) {
-            AuthCredentialPatternView.this.onCredentialChecked(matched, timeoutMs);
+        private void onPatternVerified(byte[] attestation, int timeoutMs) {
+            AuthCredentialPatternView.this.onCredentialVerified(attestation, timeoutMs);
             if (timeoutMs > 0) {
                 mLockPatternView.setEnabled(false);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 48c6621..0d9d426 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -42,7 +42,7 @@
 
 /**
  * Abstract base class for Pin, Pattern, or Password authentication, for
- * {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)}
+ * {@link BiometricPrompt.Builder#setAllowedAuthenticators(int)}}
  */
 public abstract class AuthCredentialView extends LinearLayout {
 
@@ -70,11 +70,12 @@
     protected Callback mCallback;
     protected AsyncTask<?, ?, ?> mPendingLockCheck;
     protected int mUserId;
+    protected long mOperationId;
     protected int mEffectiveUserId;
     protected ErrorTimer mErrorTimer;
 
     interface Callback {
-        void onCredentialMatched();
+        void onCredentialMatched(byte[] attestation);
     }
 
     protected static class ErrorTimer extends CountDownTimer {
@@ -148,6 +149,10 @@
         mUserId = userId;
     }
 
+    void setOperationId(long operationId) {
+        mOperationId = operationId;
+    }
+
     void setEffectiveUserId(int effectiveUserId) {
         mEffectiveUserId = effectiveUserId;
     }
@@ -245,10 +250,13 @@
 
     protected void onErrorTimeoutFinish() {}
 
-    protected void onCredentialChecked(boolean matched, int timeoutMs) {
+    protected void onCredentialVerified(byte[] attestation, int timeoutMs) {
+
+        final boolean matched = attestation != null;
+
         if (matched) {
             mClearErrorRunnable.run();
-            mCallback.onCredentialMatched();
+            mCallback.onCredentialMatched(attestation);
         } else {
             if (timeoutMs > 0) {
                 mHandler.removeCallbacks(mClearErrorRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
index 12bb122..a47621d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
@@ -17,6 +17,7 @@
 package com.android.systemui.biometrics;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 
 /**
  * Callback interface for dialog views. These should be implemented by the controller (e.g.
@@ -44,8 +45,9 @@
     /**
      * Invoked when the dialog is dismissed
      * @param reason
+     * @param credentialAttestation the HAT received from LockSettingsService upon verification
      */
-    void onDismissed(@DismissedReason int reason);
+    void onDismissed(@DismissedReason int reason, @Nullable byte[] credentialAttestation);
 
     /**
      * Invoked when the "try again" button is clicked
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index cf5a4d3..54b83c0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -207,12 +207,13 @@
 
         // Preserve new order for next repack, which sorts by last updated time.
         bubble.markUpdatedAt(mTimeSource.currentTimeMillis());
-        setSelectedBubbleInternal(bubble);
         mOverflowBubbles.remove(bubble);
-
         bubble.inflate(
-                b -> notificationEntryUpdated(bubble, /* suppressFlyout */
-                        false, /* showInShade */ true),
+                b -> {
+                    notificationEntryUpdated(bubble, /* suppressFlyout */
+                            false, /* showInShade */ true);
+                    setSelectedBubbleInternal(bubble);
+                },
                 mContext, stack, factory);
         dispatchPendingChanges();
     }
@@ -225,6 +226,14 @@
     Bubble getOrCreateBubble(NotificationEntry entry) {
         Bubble bubble = getBubbleWithKey(entry.getKey());
         if (bubble == null) {
+            for (int i = 0; i < mOverflowBubbles.size(); i++) {
+                Bubble b = mOverflowBubbles.get(i);
+                if (b.getKey().equals(entry.getKey())) {
+                    mOverflowBubbles.remove(b);
+                    mPendingBubbles.add(b);
+                    return b;
+                }
+            }
             // Check for it in pending
             for (int i = 0; i < mPendingBubbles.size(); i++) {
                 Bubble b = mPendingBubbles.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 0b7dbd2b..e666fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -424,6 +424,7 @@
 
     private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
 
+    @Nullable
     private BubbleOverflow mBubbleOverflow;
 
     private boolean mShouldShowUserEducation;
@@ -470,7 +471,8 @@
         mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
         int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
 
-        mStackAnimationController = new StackAnimationController(floatingContentCoordinator);
+        mStackAnimationController = new StackAnimationController(
+                floatingContentCoordinator, this::getBubbleCount);
 
         mExpandedAnimationController = new ExpandedAnimationController(
                 mDisplaySize, mExpandedViewPadding, res.getConfiguration().orientation);
@@ -1387,7 +1389,7 @@
             Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
         }
 
-        if (bubble.equals(mBubbleOverflow.getIconView())) {
+        if (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView())) {
             return;
         }
 
@@ -1403,7 +1405,8 @@
 
     /** Called with the coordinates to which an individual bubble has been dragged. */
     public void onBubbleDragged(View bubble, float x, float y) {
-        if (!mIsExpanded || mIsExpansionAnimating || bubble.equals(mBubbleOverflow.getIconView())) {
+        if (!mIsExpanded || mIsExpansionAnimating
+                || (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) {
             return;
         }
 
@@ -1418,7 +1421,8 @@
             Log.d(TAG, "onBubbleDragFinish: bubble=" + bubble);
         }
 
-        if (!mIsExpanded || mIsExpansionAnimating || bubble.equals(mBubbleOverflow.getIconView())) {
+        if (!mIsExpanded || mIsExpansionAnimating
+                || (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) {
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 3eaa90c..9b5dc31 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -409,11 +409,8 @@
         mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
 
         // Includes overflow button.
-        // TODO(b/148675523) this is a temporary work around; change back once we have proper fix.
-//        float totalGapWidth = getWidthForDisplayingBubbles() - (mExpandedViewPadding * 2)
-//                - (mBubblesMaxRendered + 1) * mBubbleSizePx;
-        float totalGapWidth = getAvailableScreenWidth(true /* includeStableInsets */)
-                - (mExpandedViewPadding * 2) - (mBubblesMaxRendered + 1) * mBubbleSizePx;
+        float totalGapWidth = getWidthForDisplayingBubbles() - (mExpandedViewPadding * 2)
+                - (mBubblesMaxRendered + 1) * mBubbleSizePx;
         mSpaceBetweenBubbles = totalGapWidth / mBubblesMaxRendered;
 
         // Ensure that all child views are at 1x scale, and visible, in case they were animating
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 86387f1..b63ba6f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -43,6 +43,7 @@
 import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.Set;
+import java.util.function.IntSupplier;
 
 /**
  * Animation controller for bubbles when they're in their stacked state. Stacked bubbles sit atop
@@ -241,9 +242,15 @@
         }
     };
 
+    /** Returns the number of 'real' bubbles (excluding the overflow bubble). */
+    private IntSupplier mBubbleCountSupplier;
+
     public StackAnimationController(
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            IntSupplier bubbleCountSupplier) {
         mFloatingContentCoordinator = floatingContentCoordinator;
+        mBubbleCountSupplier = bubbleCountSupplier;
+
     }
 
     /**
@@ -669,6 +676,8 @@
                 new SpringAnimation(this, firstBubbleProperty)
                         .setSpring(spring)
                         .addEndListener((dynamicAnimation, b, v, v1) -> {
+                            mRestingStackPosition.set(mStackPosition);
+
                             if (after != null) {
                                 for (Runnable callback : after) {
                                     callback.run();
@@ -736,7 +745,7 @@
             return;
         }
 
-        if (mLayout.getChildCount() == 1) {
+        if (getBubbleCount() == 1) {
             // If this is the first child added, position the stack in its starting position.
             moveStackToStartPosition();
         } else if (isStackPositionSet() && mLayout.indexOfChild(child) == 0) {
@@ -758,7 +767,7 @@
                 .start();
 
         // If there are other bubbles, pull them into the correct position.
-        if (mLayout.getChildCount() > 0) {
+        if (getBubbleCount() > 0) {
             animationForChildAtIndex(0).translationX(mStackPosition.x).start();
         } else {
             // When all children are removed ensure stack position is sane
@@ -979,6 +988,11 @@
         return mMagnetizedStack;
     }
 
+    /** Returns the number of 'real' bubbles (excluding overflow). */
+    private int getBubbleCount() {
+        return mBubbleCountSupplier.getAsInt();
+    }
+
     /**
      * FloatProperty that uses {@link #moveFirstBubbleWithStackFollowing} to set the first bubble's
      * translation and animate the rest of the stack with it. A DynamicAnimation can animate this
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 fc5663f..b439206 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.controls.ui
 
 import android.content.Context
-import android.graphics.BlendMode
 import android.graphics.drawable.ClipDrawable
+import android.graphics.drawable.GradientDrawable
 import android.graphics.drawable.LayerDrawable
 import android.service.controls.Control
 import android.service.controls.actions.ControlAction
@@ -39,6 +39,8 @@
 import kotlin.reflect.KClass
 
 private const val UPDATE_DELAY_IN_MILLIS = 3000L
+private const val ALPHA_ENABLED = (255.0 * 0.2).toInt()
+private const val ALPHA_DISABLED = 255
 
 class ControlViewHolder(
     val layout: ViewGroup,
@@ -69,7 +71,7 @@
 
         cancelUpdate?.run()
 
-        val (status, template) = cws.control?.let {
+        val (controlStatus, template) = cws.control?.let {
             title.setText(it.getTitle())
             subtitle.setText(it.getSubtitle())
             Pair(it.getStatus(), it.getControlTemplate())
@@ -80,20 +82,28 @@
         }
 
         cws.control?.let {
+            layout.setClickable(true)
             layout.setOnLongClickListener(View.OnLongClickListener() {
                 ControlActionCoordinator.longPress(this@ControlViewHolder)
                 true
             })
         }
 
-        val clazz = findBehavior(status, template)
+        val clazz = findBehavior(controlStatus, template)
         if (behavior == null || behavior!!::class != clazz) {
             // Behavior changes can signal a change in template from the app or
             // first time setup
             behavior = clazz.java.newInstance()
             behavior?.initialize(this)
+
+            // let behaviors define their own, if necessary, and clear any existing ones
+            layout.setAccessibilityDelegate(null)
         }
+
         behavior?.bind(cws)
+
+        layout.setContentDescription(
+            "${title.text} ${subtitle.text} ${status.text} ${statusExtra.text}")
     }
 
     fun actionResponse(@ControlAction.ResponseResult response: Int) {
@@ -136,16 +146,21 @@
         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())
+        val (bg, alpha) = if (enabled) {
+            Pair(ri.enabledBackground, ALPHA_ENABLED)
+        } else {
+            Pair(R.color.control_default_background, ALPHA_DISABLED)
+        }
+
         status.setTextColor(fg)
         statusExtra.setTextColor(fg)
 
         icon.setImageDrawable(ri.icon)
         icon.setImageTintList(fg)
 
-        clipLayer.getDrawable().apply {
-            setTintBlendMode(BlendMode.HUE)
-            setTintList(bg)
+        (clipLayer.getDrawable() as GradientDrawable).apply {
+            setColor(context.getResources().getColor(bg, context.getTheme()))
+            setAlpha(alpha)
         }
     }
 
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 bde966c..138cd47 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -406,7 +406,7 @@
             setText(item.getTitle())
         }
         view.requireViewById<ImageView>(R.id.app_icon).apply {
-            setContentDescription(item.getTitle())
+            setContentDescription(item.appName)
             setImageDrawable(item.icon)
         }
         return view
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 56267be..27e4649 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.ui
 
+import android.annotation.ColorRes
 import android.annotation.MainThread
 import android.content.ComponentName
 import android.content.Context
@@ -37,8 +38,11 @@
     }
 }
 
-data class RenderInfo(val icon: Drawable, val foreground: Int, val background: Int) {
-
+data class RenderInfo(
+    val icon: Drawable,
+    val foreground: Int,
+    @ColorRes val enabledBackground: Int
+) {
     companion object {
         const val APP_ICON_ID = -1
         private val iconMap = SparseArray<Drawable>()
@@ -72,6 +76,7 @@
                 icon = iconMap.get(resourceId)
                 if (icon == null) {
                     icon = context.resources.getDrawable(resourceId, null)
+                    icon.mutate()
                     iconMap.put(resourceId, icon)
                 }
             }
@@ -94,12 +99,13 @@
 
 private val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
     (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to
-        Pair(R.color.thermo_heat_foreground, R.color.thermo_heat_background),
+        Pair(R.color.thermo_heat_foreground, R.color.control_enabled_thermo_heat_background),
     (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to
-        Pair(R.color.thermo_cool_foreground, R.color.thermo_cool_background),
-    DeviceTypes.TYPE_LIGHT to Pair(R.color.light_foreground, R.color.light_background)
+        Pair(R.color.thermo_cool_foreground, R.color.control_enabled_thermo_cool_background),
+    DeviceTypes.TYPE_LIGHT
+        to Pair(R.color.light_foreground, R.color.control_enabled_light_background)
 ).withDefault {
-        Pair(R.color.control_foreground, R.color.control_background)
+        Pair(R.color.control_foreground, R.color.control_enabled_default_background)
 }
 
 private val deviceIconMap = mapOf<Int, IconState>(
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 6595b55..c495c58 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.ui
 
+import android.os.Bundle
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
@@ -24,6 +25,9 @@
 import android.view.GestureDetector.SimpleOnGestureListener
 import android.view.MotionEvent
 import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityNodeInfo
 import android.widget.TextView
 import android.service.controls.Control
 import android.service.controls.actions.FloatAction
@@ -94,6 +98,71 @@
         updateRange(currentRatio, checked)
 
         cvh.applyRenderInfo(checked)
+
+        /*
+         * This is custom widget behavior, so add a new accessibility delegate to
+         * handle clicks and range events. Present as a seek bar control.
+         */
+        cvh.layout.setAccessibilityDelegate(object : View.AccessibilityDelegate() {
+            override fun onInitializeAccessibilityNodeInfo(
+                host: View,
+                info: AccessibilityNodeInfo
+            ) {
+                super.onInitializeAccessibilityNodeInfo(host, info)
+
+                val min = levelToRangeValue(MIN_LEVEL)
+                val current = levelToRangeValue(clipLayer.getLevel())
+                val max = levelToRangeValue(MAX_LEVEL)
+
+                val step = rangeTemplate.getStepValue().toDouble()
+                val type = if (step == Math.floor(step)) {
+                    AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT
+                } else {
+                    AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_FLOAT
+                }
+
+                val rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current)
+                info.setRangeInfo(rangeInfo)
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS)
+            }
+
+            override fun performAccessibilityAction(
+                host: View,
+                action: Int,
+                arguments: Bundle?
+            ): Boolean {
+                val handled = when (action) {
+                    AccessibilityNodeInfo.ACTION_CLICK -> {
+                        ControlActionCoordinator.toggle(cvh, template.getTemplateId(),
+                            template.isChecked())
+                        true
+                    }
+                    AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS.getId() -> {
+                        if (arguments == null || !arguments.containsKey(
+                                AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)) {
+                            false
+                        } else {
+                            val value = arguments.getFloat(
+                                AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
+                            val ratioDiff = (value - rangeTemplate.getCurrentValue()) /
+                                (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
+                            updateRange(ratioDiff, template.isChecked())
+                            endUpdateRange()
+                            true
+                        }
+                    }
+                    else -> false
+                }
+
+                return handled || super.performAccessibilityAction(host, action, arguments)
+            }
+
+            override fun onRequestSendAccessibilityEvent(
+                host: ViewGroup,
+                child: View,
+                event: AccessibilityEvent
+            ): Boolean = false
+        })
     }
 
     fun beginUpdateRange() {
@@ -108,7 +177,7 @@
         clipLayer.setLevel(newLevel)
 
         if (checked) {
-            val newValue = levelToRangeValue()
+            val newValue = levelToRangeValue(clipLayer.getLevel())
             val formattedNewValue = format(rangeTemplate.getFormatString().toString(),
                     DEFAULT_FORMAT, newValue)
 
@@ -133,8 +202,8 @@
         }
     }
 
-    private fun levelToRangeValue(): Float {
-        val ratio = clipLayer.getLevel().toFloat() / MAX_LEVEL
+    private fun levelToRangeValue(i: Int): Float {
+        val ratio = i.toFloat() / MAX_LEVEL
         return rangeTemplate.getMinValue() +
             (ratio * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()))
     }
@@ -143,7 +212,8 @@
         statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
                 .getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
         status.setVisibility(View.VISIBLE)
-        cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(levelToRangeValue())))
+        cvh.action(FloatAction(rangeTemplate.getTemplateId(),
+            findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
     }
 
     fun findNearestStep(value: Float): Float {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index c45063a..f6fccc0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -161,15 +161,8 @@
             }
 
             int scrimOpacity = -1;
-            if (mPaused || mScreenOff) {
-                // If AOD is paused, force the screen black until the
-                // sensor reports a new brightness. This ensures that when the screen comes on
-                // again, it will only show after the brightness sensor has stabilized,
-                // avoiding a potential flicker.
-                scrimOpacity = 255;
-            } else if (!mScreenOff && mLightSensor == null) {
-                // No light sensor but previous state turned the screen black. Make the scrim
-                // transparent and below views visible.
+            if (mLightSensor == null) {
+                // No light sensor, scrims are always transparent.
                 scrimOpacity = 0;
             } else if (brightnessReady) {
                 // Only unblank scrim once brightness is ready.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 27c81ce..b99d765 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -100,6 +100,7 @@
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -115,16 +116,17 @@
 import javax.inject.Inject;
 
 /**
- * Helper to show the global actions dialog.  Each item is an {@link Action} that
- * may show depending on whether the keyguard is showing, and whether the device
- * is provisioned.
+ * Helper to show the global actions dialog.  Each item is an {@link Action} that may show depending
+ * on whether the keyguard is showing, and whether the device is provisioned.
  */
 public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
-        DialogInterface.OnShowListener, ConfigurationController.ConfigurationListener {
+        DialogInterface.OnShowListener,
+        ConfigurationController.ConfigurationListener,
+        GlobalActionsPanelPlugin.Callbacks {
 
-    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
-    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
-    static public final String SYSTEM_DIALOG_REASON_DREAM = "dream";
+    public static final String SYSTEM_DIALOG_REASON_KEY = "reason";
+    public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
+    public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
 
     private static final String TAG = "GlobalActionsDialog";
 
@@ -162,6 +164,7 @@
     private final IActivityManager mIActivityManager;
     private final TelecomManager mTelecomManager;
     private final MetricsLogger mMetricsLogger;
+    private final NotificationShadeDepthController mDepthController;
     private final BlurUtils mBlurUtils;
 
     private ArrayList<Action> mItems;
@@ -207,8 +210,8 @@
             KeyguardStateController keyguardStateController, UserManager userManager,
             TrustManager trustManager, IActivityManager iActivityManager,
             @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
-            BlurUtils blurUtils, SysuiColorExtractor colorExtractor,
-            IStatusBarService statusBarService,
+            NotificationShadeDepthController depthController, SysuiColorExtractor colorExtractor,
+            IStatusBarService statusBarService, BlurUtils blurUtils,
             NotificationShadeWindowController notificationShadeWindowController,
             ControlsUiController controlsUiController, IWindowManager iWindowManager,
             @Background Executor backgroundExecutor,
@@ -229,7 +232,7 @@
         mIActivityManager = iActivityManager;
         mTelecomManager = telecomManager;
         mMetricsLogger = metricsLogger;
-        mBlurUtils = blurUtils;
+        mDepthController = depthController;
         mSysuiColorExtractor = colorExtractor;
         mStatusBarService = statusBarService;
         mNotificationShadeWindowController = notificationShadeWindowController;
@@ -237,6 +240,7 @@
         mIWindowManager = iWindowManager;
         mBackgroundExecutor = backgroundExecutor;
         mControlsListingController = controlsListingController;
+        mBlurUtils = blurUtils;
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -268,8 +272,9 @@
             @Override
             public void onUnlockedChanged() {
                 if (mDialog != null && mDialog.mPanelController != null) {
-                    boolean locked = !keyguardStateController.canDismissLockScreen();
-                    mDialog.mPanelController.onDeviceLockStateChanged(locked);
+                    boolean unlocked = keyguardStateController.isUnlocked()
+                            || keyguardStateController.canDismissLockScreen();
+                    mDialog.mPanelController.onDeviceLockStateChanged(unlocked);
                 }
             }
         });
@@ -383,7 +388,7 @@
                 mItems.add(getSettingsAction());
             } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
                 if (Settings.Secure.getIntForUser(mContentResolver,
-                            Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, getCurrentUser().id) != 0
+                        Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, getCurrentUser().id) != 0
                         && shouldDisplayLockdown()) {
                     mItems.add(getLockdownAction());
                 }
@@ -417,29 +422,10 @@
 
         mAdapter = new MyAdapter();
 
-        GlobalActionsPanelPlugin.PanelViewController panelViewController =
-                mPanelPlugin != null
-                        ? mPanelPlugin.onPanelShown(
-                                new GlobalActionsPanelPlugin.Callbacks() {
-                                    @Override
-                                    public void dismissGlobalActionsMenu() {
-                                        dismissDialog();
-                                    }
-
-                                    @Override
-                                    public void startPendingIntentDismissingKeyguard(
-                                            PendingIntent intent) {
-                                        mActivityStarter
-                                                .startPendingIntentDismissingKeyguard(intent);
-                                    }
-                                },
-                                !mKeyguardStateController.isUnlocked())
-                        : null;
-
-        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController,
-                mBlurUtils, mSysuiColorExtractor, mStatusBarService,
+        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, getWalletPanelViewController(),
+                mDepthController, mSysuiColorExtractor, mStatusBarService,
                 mNotificationShadeWindowController,
-                shouldShowControls() ? mControlsUiController : null);
+                shouldShowControls() ? mControlsUiController : null, mBlurUtils);
         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
         dialog.setKeyguardShowing(mKeyguardShowing);
 
@@ -474,6 +460,33 @@
         mConfigurationController.removeCallback(this);
     }
 
+    @Nullable
+    private GlobalActionsPanelPlugin.PanelViewController getWalletPanelViewController() {
+        if (mPanelPlugin == null) {
+            return null;
+        }
+        return mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());
+    }
+
+    /**
+     * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
+     * called when the quick access wallet requests dismissal.
+     */
+    @Override
+    public void dismissGlobalActionsMenu() {
+        dismissDialog();
+    }
+
+    /**
+     * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is
+     * called when the quick access wallet requests that an intent be started (with lock screen
+     * shown first if needed).
+     */
+    @Override
+    public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
+        mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
+    }
+
     private final class PowerAction extends SinglePressAction implements LongPressAction {
         private PowerAction() {
             super(R.drawable.ic_lock_power_off,
@@ -916,7 +929,9 @@
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void onDismiss(DialogInterface dialog) {
         if (mDialog == dialog) {
             mDialog = null;
@@ -932,17 +947,19 @@
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void onShow(DialogInterface dialog) {
         mMetricsLogger.visible(MetricsEvent.POWER_MENU);
     }
 
     /**
-     * The adapter used for the list within the global actions dialog, taking
-     * into account whether the keyguard is showing via
-     * {@link com.android.systemui.globalactions.GlobalActionsDialog#mKeyguardShowing} and whether
-     * the device is provisioned
-     * via {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}.
+     * The adapter used for the list within the global actions dialog, taking into account whether
+     * the keyguard is showing via
+     * {@link com.android.systemui.globalactions.GlobalActionsDialog#mKeyguardShowing}
+     * and whether the device is provisioned via
+     * {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}.
      */
     public class MyAdapter extends MultiListAdapter {
         private int countItems(boolean separated) {
@@ -1073,8 +1090,7 @@
      */
     public interface Action {
         /**
-         * @return Text that will be announced when dialog is created.  null
-         * for none.
+         * @return Text that will be announced when dialog is created.  null for none.
          */
         CharSequence getLabelForAccessibility(Context context);
 
@@ -1083,15 +1099,13 @@
         void onPress();
 
         /**
-         * @return whether this action should appear in the dialog when the keygaurd
-         * is showing.
+         * @return whether this action should appear in the dialog when the keygaurd is showing.
          */
         boolean showDuringKeyguard();
 
         /**
-         * @return whether this action should appear in the dialog before the
-         * device is provisioned.onlongpress
-         *
+         * @return whether this action should appear in the dialog before the device is
+         * provisioned.onlongpress
          */
         boolean showBeforeProvisioning();
 
@@ -1110,8 +1124,7 @@
     }
 
     /**
-     * A single press action maintains no state, just responds to a press
-     * and takes an action.
+     * A single press action maintains no state, just responds to a press and takes an action.
      */
 
     private abstract class SinglePressAction implements Action {
@@ -1185,8 +1198,8 @@
     }
 
     /**
-     * A toggle action knows whether it is on or off, and displays an icon
-     * and status message accordingly.
+     * A toggle action knows whether it is on or off, and displays an icon and status message
+     * accordingly.
      */
     private static abstract class ToggleAction implements Action {
 
@@ -1236,8 +1249,7 @@
         }
 
         /**
-         * Override to make changes to resource IDs just before creating the
-         * View.
+         * Override to make changes to resource IDs just before creating the View.
          */
         void willCreate() {
 
@@ -1293,9 +1305,9 @@
         }
 
         /**
-         * Implementations may override this if their state can be in on of the intermediate
-         * states until some notification is received (e.g airplane mode is 'turning off' until
-         * we know the wireless connections are back online
+         * Implementations may override this if their state can be in on of the intermediate states
+         * until some notification is received (e.g airplane mode is 'turning off' until we know the
+         * wireless connections are back online
          *
          * @param buttonOn Whether the button was turned on or off
          */
@@ -1313,12 +1325,13 @@
     private class AirplaneModeAction extends ToggleAction {
         AirplaneModeAction() {
             super(
-                R.drawable.ic_lock_airplane_mode,
-                R.drawable.ic_lock_airplane_mode_off,
-                R.string.global_actions_toggle_airplane_mode,
-                R.string.global_actions_airplane_mode_on_status,
-                R.string.global_actions_airplane_mode_off_status);
+                    R.drawable.ic_lock_airplane_mode,
+                    R.drawable.ic_lock_airplane_mode_off,
+                    R.string.global_actions_toggle_airplane_mode,
+                    R.string.global_actions_airplane_mode_on_status,
+                    R.string.global_actions_airplane_mode_off_status);
         }
+
         void onToggle(boolean on) {
             if (mHasTelephony && TelephonyProperties.in_ecm_mode().orElse(false)) {
                 mIsWaitingForEcmExit = true;
@@ -1570,24 +1583,27 @@
         private ResetOrientationData mResetOrientationData;
         private boolean mHadTopUi;
         private final NotificationShadeWindowController mNotificationShadeWindowController;
+        private final NotificationShadeDepthController mDepthController;
         private final BlurUtils mBlurUtils;
 
         private ControlsUiController mControlsUiController;
         private ViewGroup mControlsView;
 
         ActionsDialog(Context context, MyAdapter adapter,
-                GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
+                GlobalActionsPanelPlugin.PanelViewController plugin,
+                NotificationShadeDepthController depthController,
                 SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
                 NotificationShadeWindowController notificationShadeWindowController,
-                ControlsUiController controlsUiController) {
+                ControlsUiController controlsUiController, BlurUtils blurUtils) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
             mContext = context;
             mAdapter = adapter;
-            mBlurUtils = blurUtils;
+            mDepthController = depthController;
             mColorExtractor = sysuiColorExtractor;
             mStatusBarService = statusBarService;
             mNotificationShadeWindowController = notificationShadeWindowController;
             mControlsUiController = controlsUiController;
+            mBlurUtils = blurUtils;
 
             // Window initialization
             Window window = getWindow();
@@ -1601,11 +1617,11 @@
             window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
             window.addFlags(
                     WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
-                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                            | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                            | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
             window.getAttributes().setFitInsetsTypes(0 /* types */);
             setTitle(R.string.global_actions);
@@ -1696,7 +1712,8 @@
             }
             if (mBackgroundDrawable == null) {
                 mBackgroundDrawable = new ScrimDrawable();
-                mScrimAlpha = ScrimController.BUSY_SCRIM_ALPHA;
+                mScrimAlpha = mBlurUtils.supportsBlursOnWindows()
+                        ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA;
             }
             getWindow().setBackgroundDrawable(mBackgroundDrawable);
         }
@@ -1748,7 +1765,8 @@
 
         /**
          * Updates background and system bars according to current GradientColors.
-         * @param colors Colors and hints to use.
+         *
+         * @param colors  Colors and hints to use.
          * @param animate Interpolates gradient if true, just sets otherwise.
          */
         private void updateColors(GradientColors colors, boolean animate) {
@@ -1792,8 +1810,8 @@
                         float animatedValue = animation.getAnimatedFraction();
                         int alpha = (int) (animatedValue * mScrimAlpha * 255);
                         mBackgroundDrawable.setAlpha(alpha);
-                        mBlurUtils.applyBlur(mGlobalActionsLayout.getViewRootImpl(),
-                                mBlurUtils.blurRadiusOfRatio(animatedValue));
+                        mDepthController.updateGlobalDialogVisibility(animatedValue,
+                                mGlobalActionsLayout);
                     })
                     .start();
             if (mControlsUiController != null) {
@@ -1822,8 +1840,8 @@
                         float animatedValue = 1f - animation.getAnimatedFraction();
                         int alpha = (int) (animatedValue * mScrimAlpha * 255);
                         mBackgroundDrawable.setAlpha(alpha);
-                        mBlurUtils.applyBlur(mGlobalActionsLayout.getViewRootImpl(),
-                                mBlurUtils.blurRadiusOfRatio(animatedValue));
+                        mDepthController.updateGlobalDialogVisibility(animatedValue,
+                                mGlobalActionsLayout);
                     })
                     .start();
             dismissPanel();
@@ -1914,8 +1932,8 @@
     }
 
     /**
-     * Determines whether or not the Global Actions menu should be forced to
-     * use the newer grid-style layout.
+     * Determines whether or not the Global Actions menu should be forced to use the newer
+     * grid-style layout.
      */
     private static boolean isForceGridEnabled(Context context) {
         return isPanelDebugModeEnabled(context);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index bbb57bd..12955a1 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -149,7 +149,7 @@
         }
 
         if (mBlurUtils.supportsBlursOnWindows()) {
-            background.setAlpha((int) (ScrimController.BUSY_SCRIM_ALPHA * 255));
+            background.setAlpha((int) (ScrimController.BLUR_SCRIM_ALPHA * 255));
             mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
                         mBlurUtils.blurRadiusOfRatio(1));
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3d708a9..226ac16c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -91,8 +91,10 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NavigationModeController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -374,6 +376,7 @@
 
     private boolean mLockLater;
     private boolean mShowHomeOverLockscreen;
+    private boolean mInGestureNavigationMode;
 
     private boolean mWakeAndUnlocking;
     private IKeyguardDrawnCallback mDrawnCallback;
@@ -720,7 +723,8 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager,
             @UiBackground Executor uiBgExecutor, PowerManager powerManager,
             TrustManager trustManager,
-            DeviceConfigProxy deviceConfig) {
+            DeviceConfigProxy deviceConfig,
+            NavigationModeController navigationModeController) {
         super(context);
         mFalsingManager = falsingManager;
         mLockPatternUtils = lockPatternUtils;
@@ -742,6 +746,10 @@
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 mHandler::post,
                 mOnPropertiesChangedListener);
+        mInGestureNavigationMode =
+                QuickStepContract.isGesturalMode(navigationModeController.addListener(mode -> {
+                    mInGestureNavigationMode = QuickStepContract.isGesturalMode(mode);
+                }));
     }
 
     public void userActivity() {
@@ -2013,7 +2021,7 @@
             // windows that appear on top, ever
             int flags = StatusBarManager.DISABLE_NONE;
             if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) {
-                if (!mShowHomeOverLockscreen) {
+                if (!mShowHomeOverLockscreen || !mInGestureNavigationMode) {
                     flags |= StatusBarManager.DISABLE_HOME;
                 }
                 flags |= StatusBarManager.DISABLE_RECENT;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index ae380b7..c281ece 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -93,7 +93,7 @@
             return mIatm.startActivityAsUser(
                     mContext.getIApplicationThread() /*caller*/,
                     mContext.getBasePackageName() /*callingPackage*/,
-                    mContext.getFeatureId() /*callingFeatureId*/,
+                    mContext.getAttributionTag() /*callingAttributionTag*/,
                     intent /*intent*/,
                     intent.resolveTypeIfNeeded(mContext.getContentResolver()) /*resolvedType*/,
                     null /*resultTo*/,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 9be4786..7a63a5e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -29,6 +29,7 @@
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.statusbar.phone.NavigationModeController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.DeviceConfigProxy;
@@ -64,7 +65,8 @@
             PowerManager powerManager,
             TrustManager trustManager,
             @UiBackground Executor uiBgExecutor,
-            DeviceConfigProxy deviceConfig) {
+            DeviceConfigProxy deviceConfig,
+            NavigationModeController navigationModeController) {
         return new KeyguardViewMediator(
                 context,
                 falsingManager,
@@ -78,6 +80,7 @@
                 uiBgExecutor,
                 powerManager,
                 trustManager,
-                deviceConfig);
+                deviceConfig,
+                navigationModeController);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 67802bc..4bfcf22 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -30,6 +30,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+import javax.inject.Inject;
+
 /**
  * Controller class of PiP animations (both from and to PiP mode).
  */
@@ -37,7 +39,6 @@
     private static final float FRACTION_START = 0f;
     private static final float FRACTION_END = 1f;
 
-    public static final int DURATION_DEFAULT_MS = 425;
     public static final int ANIM_TYPE_BOUNDS = 0;
     public static final int ANIM_TYPE_ALPHA = 1;
 
@@ -63,12 +64,15 @@
     @interface TransitionDirection {}
 
     private final Interpolator mFastOutSlowInInterpolator;
+    private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
 
     private PipTransitionAnimator mCurrentAnimator;
 
-    PipAnimationController(Context context) {
+    @Inject
+    PipAnimationController(Context context, PipSurfaceTransactionHelper helper) {
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
+        mSurfaceTransactionHelper = helper;
     }
 
     @SuppressWarnings("unchecked")
@@ -111,6 +115,7 @@
     }
 
     private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) {
+        animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
         animator.setInterpolator(mFastOutSlowInInterpolator);
         animator.setFloatValues(FRACTION_START, FRACTION_END);
         return animator;
@@ -152,9 +157,10 @@
         private T mEndValue;
         private T mCurrentValue;
         private PipAnimationCallback mPipAnimationCallback;
-        private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory;
+        private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+                mSurfaceControlTransactionFactory;
+        private PipSurfaceTransactionHelper mSurfaceTransactionHelper;
         private @TransitionDirection int mTransitionDirection;
-        private int mCornerRadius;
 
         private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType,
                 Rect destinationBounds, T startValue, T endValue) {
@@ -243,15 +249,6 @@
             mCurrentValue = value;
         }
 
-        int getCornerRadius() {
-            return mCornerRadius;
-        }
-
-        PipTransitionAnimator<T> setCornerRadius(int cornerRadius) {
-            mCornerRadius = cornerRadius;
-            return this;
-        }
-
         boolean shouldApplyCornerRadius() {
             return mTransitionDirection != TRANSITION_DIRECTION_TO_FULLSCREEN;
         }
@@ -274,10 +271,19 @@
         }
 
         @VisibleForTesting
-        void setSurfaceControlTransactionFactory(SurfaceControlTransactionFactory factory) {
+        void setSurfaceControlTransactionFactory(
+                PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
             mSurfaceControlTransactionFactory = factory;
         }
 
+        PipSurfaceTransactionHelper getSurfaceTransactionHelper() {
+            return mSurfaceTransactionHelper;
+        }
+
+        void setSurfaceTransactionHelper(PipSurfaceTransactionHelper helper) {
+            mSurfaceTransactionHelper = helper;
+        }
+
         abstract void applySurfaceControlTransaction(SurfaceControl leash,
                 SurfaceControl.Transaction tx, float fraction);
 
@@ -290,14 +296,11 @@
                         SurfaceControl.Transaction tx, float fraction) {
                     final float alpha = getStartValue() * (1 - fraction) + getEndValue() * fraction;
                     setCurrentValue(alpha);
-                    tx.setAlpha(leash, alpha);
+                    getSurfaceTransactionHelper().alpha(tx, leash, alpha);
                     if (Float.compare(fraction, FRACTION_START) == 0) {
-                        // Ensure the start condition
-                        final Rect bounds = getDestinationBounds();
-                        tx.setPosition(leash, bounds.left, bounds.top)
-                                .setWindowCrop(leash, bounds.width(), bounds.height());
-                        tx.setCornerRadius(leash,
-                                shouldApplyCornerRadius() ? getCornerRadius() : 0);
+                        getSurfaceTransactionHelper()
+                                .crop(tx, leash, getDestinationBounds())
+                                .round(tx, leash, shouldApplyCornerRadius());
                     }
                     tx.apply();
                 }
@@ -326,21 +329,16 @@
                             getCastedFractionValue(start.right, end.right, fraction),
                             getCastedFractionValue(start.bottom, end.bottom, fraction));
                     setCurrentValue(mTmpRect);
-                    tx.setPosition(leash, mTmpRect.left, mTmpRect.top)
-                            .setWindowCrop(leash, mTmpRect.width(), mTmpRect.height());
+                    getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
                     if (Float.compare(fraction, FRACTION_START) == 0) {
                         // Ensure the start condition
-                        tx.setAlpha(leash, 1f);
-                        tx.setCornerRadius(leash,
-                                shouldApplyCornerRadius() ? getCornerRadius() : 0);
+                        getSurfaceTransactionHelper()
+                                .alpha(tx, leash, 1f)
+                                .round(tx, leash, shouldApplyCornerRadius());
                     }
                     tx.apply();
                 }
             };
         }
     }
-
-    interface SurfaceControlTransactionFactory {
-        SurfaceControl.Transaction getTransaction();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index fb348f4..88491b7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -67,7 +67,7 @@
 
     private ComponentName mLastPipComponentName;
     private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
-    private Size mReentrySize = null;
+    private Size mReentrySize;
 
     private float mDefaultAspectRatio;
     private float mMinAspectRatio;
@@ -77,6 +77,7 @@
     private int mDefaultMinSize;
     private Point mScreenEdgeInsets;
     private int mCurrentMinSize;
+    private Size mOverrideMinimalSize;
 
     private boolean mIsImeShowing;
     private int mImeHeight;
@@ -226,11 +227,14 @@
     /**
      * @return {@link Rect} of the destination PiP window bounds.
      */
-    Rect getDestinationBounds(float aspectRatio, Rect bounds) {
+    Rect getDestinationBounds(float aspectRatio, Rect bounds, Size minimalSize) {
         final Rect destinationBounds;
         final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
         if (bounds == null) {
             destinationBounds = new Rect(defaultBounds);
+            if (mReentrySnapFraction == INVALID_SNAP_FRACTION && mReentrySize == null) {
+                mOverrideMinimalSize = minimalSize;
+            }
         } else {
             destinationBounds = new Rect(bounds);
         }
@@ -335,7 +339,6 @@
      */
     private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
             boolean useCurrentMinEdgeSize) {
-
         // Save the snap fraction and adjust the size based on the new aspect ratio.
         final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                 getMovementBounds(stackBounds));
@@ -354,10 +357,38 @@
         final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
         final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
         stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
+        // apply the override minimal size if applicable, this minimal size is specified by app
+        if (mOverrideMinimalSize != null) {
+            transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize);
+        }
         mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
     }
 
     /**
+     * Transforms a given bounds to meet the minimal size constraints.
+     * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}.
+     */
+    private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio,
+            Size minimalSize) {
+        if (minimalSize == null) return;
+        final Size adjustedMinimalSize;
+        final float minimalSizeAspectRatio =
+                minimalSize.getWidth() / (float) minimalSize.getHeight();
+        if (minimalSizeAspectRatio > aspectRatio) {
+            // minimal size is wider, fixed the width and increase the height
+            adjustedMinimalSize = new Size(
+                    minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio));
+        } else {
+            adjustedMinimalSize = new Size(
+                    (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight());
+        }
+        final Rect containerBounds = new Rect(stackBounds);
+        Gravity.apply(mDefaultStackGravity,
+                adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(),
+                containerBounds, stackBounds);
+    }
+
+    /**
      * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
      * provided, then it will apply the default bounds to the provided snap fraction and size.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
new file mode 100644
index 0000000..21f9301
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -0,0 +1,81 @@
+/*
+ * 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.pip;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import com.android.systemui.R;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
+ */
+@Singleton
+public class PipSurfaceTransactionHelper {
+
+    private final boolean mEnableCornerRadius;
+    private final int mCornerRadius;
+
+    @Inject
+    public PipSurfaceTransactionHelper(Context context) {
+        final Resources res = context.getResources();
+        mEnableCornerRadius = res.getBoolean(R.bool.config_pipEnableRoundCorner);
+        mCornerRadius = res.getDimensionPixelSize(R.dimen.pip_corner_radius);
+    }
+
+    /**
+     * Operates the alpha on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
+            float alpha) {
+        tx.setAlpha(leash, alpha);
+        return this;
+    }
+
+    /**
+     * Operates the crop (and position) on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
+            Rect destinationBounds) {
+        tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
+                .setPosition(leash, destinationBounds.left, destinationBounds.top);
+        return this;
+    }
+
+    /**
+     * Operates the round corner radius on a given transaction and leash
+     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+     */
+    PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
+            boolean applyCornerRadius) {
+        if (mEnableCornerRadius) {
+            tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
+        }
+        return this;
+    }
+
+    interface SurfaceControlTransactionFactory {
+        SurfaceControl.Transaction getTransaction();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 51113ac..4076c1b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
-import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
@@ -31,12 +30,13 @@
 import android.app.ITaskOrganizerController;
 import android.app.PictureInPictureParams;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 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.util.Size;
 import android.view.ITaskOrganizer;
 import android.view.IWindowContainer;
 import android.view.SurfaceControl;
@@ -47,9 +47,7 @@
 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;
 
@@ -79,8 +77,8 @@
     private final PipAnimationController mPipAnimationController;
     private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
     private final Rect mLastReportedBounds = new Rect();
-    private final int mCornerRadius;
-    private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
+    private final int mEnterExitAnimationDuration;
+    private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
 
     // These callbacks are called on the update thread
     private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -172,14 +170,20 @@
     private SurfaceControl mLeash;
     private boolean mInPip;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+    private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+            mSurfaceControlTransactionFactory;
 
-    public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) {
+    public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
+            @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper) {
         mMainHandler = new Handler(Looper.getMainLooper());
         mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
         mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController();
         mPipBoundsHandler = boundsHandler;
-        mPipAnimationController = new PipAnimationController(context);
-        mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+        mEnterExitAnimationDuration = context.getResources()
+                .getInteger(R.integer.config_pipResizeAnimationDuration);
+        mSurfaceTransactionHelper = surfaceTransactionHelper;
+        mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper);
+        mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
     }
 
     public Handler getUpdateHandler() {
@@ -202,26 +206,12 @@
         mOneShotAnimationType = animationType;
     }
 
-    /**
-     * Callback to issue the final {@link WindowContainerTransaction} on end of movements.
-     * @param destinationBounds the final bounds.
-     */
-    public void onMotionMovementEnd(Rect destinationBounds) {
-        try {
-            mLastReportedBounds.set(destinationBounds);
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.setBounds(mToken, destinationBounds);
-            mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to apply window container transaction", e);
-        }
-    }
-
     @Override
     public void taskAppeared(ActivityManager.RunningTaskInfo info) {
         Objects.requireNonNull(info, "Requires RunningTaskInfo");
         final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
+                getAspectRatioOrDefault(info.pictureInPictureParams),
+                null /* bounds */, getMinimalSize(info.topActivityInfo));
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
         mTaskInfo = info;
         mToken = mTaskInfo.token;
@@ -232,17 +222,15 @@
             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) {
             scheduleAnimateResizePip(currentBounds, destinationBounds,
-                    TRANSITION_DIRECTION_TO_PIP, DURATION_DEFAULT_MS, null);
+                    TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
             mUpdateHandler.post(() -> mPipAnimationController
                     .getAnimator(mLeash, destinationBounds, 0f, 1f)
                     .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
-                    .setCornerRadius(mCornerRadius)
                     .setPipAnimationCallback(mPipAnimationCallback)
-                    .setDuration(DURATION_DEFAULT_MS)
+                    .setDuration(mEnterExitAnimationDuration)
                     .start());
             mOneShotAnimationType = ANIM_TYPE_BOUNDS;
         } else {
@@ -258,9 +246,9 @@
             Log.wtf(TAG, "Unrecognized token: " + token);
             return;
         }
-        final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder());
-        scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore,
-                TRANSITION_DIRECTION_TO_FULLSCREEN, DURATION_DEFAULT_MS, null);
+        scheduleAnimateResizePip(mLastReportedBounds,
+                info.configuration.windowConfiguration.getBounds(),
+                TRANSITION_DIRECTION_TO_FULLSCREEN, mEnterExitAnimationDuration, null);
         mInPip = false;
     }
 
@@ -276,9 +264,10 @@
             return;
         }
         final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                getAspectRatioOrDefault(newParams), null /* bounds */);
+                getAspectRatioOrDefault(newParams),
+                null /* bounds */, getMinimalSize(info.topActivityInfo));
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
-        scheduleAnimateResizePip(destinationBounds, DURATION_DEFAULT_MS, null);
+        scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration, null);
     }
 
     /**
@@ -305,7 +294,6 @@
     private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
             @PipAnimationController.TransitionDirection int direction, int durationMs,
             Consumer<Rect> updateBoundsCallback) {
-        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
         if (!mInPip) {
             // Ignore animation when we are no longer in PIP
             return;
@@ -324,7 +312,6 @@
      * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
      */
     public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
-        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = updateBoundsCallback;
         args.arg2 = toBounds;
@@ -332,22 +319,20 @@
     }
 
     /**
-     * Finish a intermediate resize operation. This is expected to be called after
+     * Finish an intermediate resize operation. This is expected to be called after
      * {@link #scheduleResizePip}.
      */
     public void scheduleFinishResizePip(Rect destinationBounds) {
-        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
-        SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
-                .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
-                .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
-                .setCornerRadius(mLeash, mInPip ? mCornerRadius : 0);
+        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+        mSurfaceTransactionHelper
+                .crop(tx, mLeash, destinationBounds)
+                .round(tx, mLeash, mInPip);
         scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, null);
     }
 
     private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
             Rect destinationBounds, @PipAnimationController.TransitionDirection int direction,
             Consumer<Rect> updateBoundsCallback) {
-        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = updateBoundsCallback;
         args.arg2 = tx;
@@ -365,7 +350,6 @@
             // Ignore offsets when we are no longer in PIP
             return;
         }
-        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = updateBoundsCallback;
         args.arg2 = originalBounds;
@@ -394,17 +378,16 @@
             throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
                     + "directly");
         }
-        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
         // Could happen when dismissPip
         if (mToken == null || mLeash == null) {
             Log.w(TAG, "Abort animation, invalid leash");
             return;
         }
-        new SurfaceControl.Transaction()
-                .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
-                .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
-                .setCornerRadius(mLeash, mInPip ? mCornerRadius : 0)
-                .apply();
+        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+        mSurfaceTransactionHelper
+                .crop(tx, mLeash, destinationBounds)
+                .round(tx, mLeash, mInPip);
+        tx.apply();
     }
 
     private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
@@ -447,12 +430,19 @@
         mUpdateHandler.post(() -> mPipAnimationController
                 .getAnimator(mLeash, currentBounds, destinationBounds)
                 .setTransitionDirection(direction)
-                .setCornerRadius(mCornerRadius)
                 .setPipAnimationCallback(mPipAnimationCallback)
                 .setDuration(durationMs)
                 .start());
     }
 
+    private Size getMinimalSize(ActivityInfo activityInfo) {
+        if (activityInfo == null || activityInfo.windowLayout == null) {
+            return null;
+        }
+        final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout;
+        return new Size(windowLayout.minWidth, windowLayout.minHeight);
+    }
+
     private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
         return params == null
                 ? mPipBoundsHandler.getDefaultAspectRatio()
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 32e9a03..020627a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -42,6 +42,7 @@
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipSnapAlgorithm;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -210,7 +211,8 @@
             FloatingContentCoordinator floatingContentCoordinator,
             DeviceConfigProxy deviceConfig,
             PipBoundsHandler pipBoundsHandler,
-            PipSnapAlgorithm pipSnapAlgorithm) {
+            PipSnapAlgorithm pipSnapAlgorithm,
+            PipSurfaceTransactionHelper surfaceTransactionHelper) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
 
@@ -224,7 +226,8 @@
 
         final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
         mPipBoundsHandler = pipBoundsHandler;
-        mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
+        mPipTaskOrganizer = new PipTaskOrganizer(context, pipBoundsHandler,
+                surfaceTransactionHelper);
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mInputConsumerController = InputConsumerController.getPipInputConsumer();
         mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
@@ -237,6 +240,12 @@
                 mTouchHandler.getMotionHelper());
         displayController.addDisplayChangingController(mRotationController);
 
+        // Ensure that we have the display info in case we get calls to update the bounds before the
+        // listener calls back
+        final DisplayInfo displayInfo = new DisplayInfo();
+        context.getDisplay().getDisplayInfo(displayInfo);
+        mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
+
         try {
             ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer(
                     mPipTaskOrganizer, WINDOWING_MODE_PINNED);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 33760be..449a2bc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -78,10 +78,10 @@
     private final Rect mBounds = new Rect();
 
     /** The bounds within which PIP's top-left coordinate is allowed to move. */
-    private Rect mMovementBounds = new Rect();
+    private final Rect mMovementBounds = new Rect();
 
     /** The region that all of PIP must stay within. */
-    private Rect mFloatingAllowedArea = new Rect();
+    private final Rect mFloatingAllowedArea = new Rect();
 
     /**
      * Bounds that are animated using the physics animator.
@@ -89,7 +89,7 @@
     private final Rect mAnimatedBounds = new Rect();
 
     /** The destination bounds to which PIP is animating. */
-    private Rect mAnimatingToBounds = new Rect();
+    private final Rect mAnimatingToBounds = new Rect();
 
     /** Coordinator instance for resolving conflicts with other floating content. */
     private FloatingContentCoordinator mFloatingContentCoordinator;
@@ -120,7 +120,7 @@
                 new PhysicsAnimator.SpringConfig(
                         SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
 
-    private final Consumer<Rect> mUpdateBoundsCallback = (toBounds) -> mBounds.set(toBounds);
+    private final Consumer<Rect> mUpdateBoundsCallback = mBounds::set;
 
     public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
             PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
@@ -426,7 +426,7 @@
         cancelAnimations();
 
         mAnimatedBoundsPhysicsAnimator
-                .withEndActions(() ->  mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds))
+                .withEndActions(() ->  mPipTaskOrganizer.scheduleFinishResizePip(mAnimatedBounds))
                 .addUpdateListener(mResizePipUpdateListener)
                 .start();
     }
@@ -437,7 +437,7 @@
      * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}.
      */
     private void setAnimatingToBounds(Rect bounds) {
-        mAnimatingToBounds = bounds;
+        mAnimatingToBounds.set(bounds);
         mFloatingContentCoordinator.onContentMoved(this);
     }
 
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 0c5a4d7..050acd5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,8 +20,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
-import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
-
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
@@ -53,6 +51,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
@@ -136,6 +135,7 @@
     private String[] mLastPackagesResourceGranted;
     private PipNotification mPipNotification;
     private ParceledListSlice mCustomActions;
+    private int mResizeAnimationDuration;
 
     // Used to calculate the movement bounds
     private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
@@ -230,7 +230,8 @@
 
     @Inject
     public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
-            PipBoundsHandler pipBoundsHandler) {
+            PipBoundsHandler pipBoundsHandler,
+            PipSurfaceTransactionHelper surfaceTransactionHelper) {
         if (mInitialized) {
             return;
         }
@@ -238,7 +239,10 @@
         mInitialized = true;
         mContext = context;
         mPipBoundsHandler = pipBoundsHandler;
-        mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
+        mResizeAnimationDuration = context.getResources()
+                .getInteger(R.integer.config_pipResizeAnimationDuration);
+        mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
+                surfaceTransactionHelper);
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mActivityTaskManager = ActivityTaskManager.getService();
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -436,7 +440,8 @@
                 mCurrentPipBounds = mPipBounds;
                 break;
         }
-        mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, DURATION_DEFAULT_MS, null);
+        mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration,
+                null);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 9ab4714..bf72b33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -44,6 +44,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.InfoMediaManager;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 import com.android.systemui.Dependency;
@@ -98,6 +100,7 @@
     private final LinearLayout mMediaCarousel;
     private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>();
     private final NotificationMediaManager mNotificationMediaManager;
+    private final LocalBluetoothManager mLocalBluetoothManager;
     private final Executor mBackgroundExecutor;
     private LocalMediaManager mLocalMediaManager;
     private MediaDevice mDevice;
@@ -157,7 +160,8 @@
             BroadcastDispatcher broadcastDispatcher,
             QSLogger qsLogger,
             NotificationMediaManager notificationMediaManager,
-            @Background Executor backgroundExecutor
+            @Background Executor backgroundExecutor,
+            @Nullable LocalBluetoothManager localBluetoothManager
     ) {
         super(context, attrs);
         mContext = context;
@@ -165,6 +169,7 @@
         mDumpManager = dumpManager;
         mNotificationMediaManager = notificationMediaManager;
         mBackgroundExecutor = backgroundExecutor;
+        mLocalBluetoothManager = localBluetoothManager;
 
         setOrientation(VERTICAL);
 
@@ -286,7 +291,9 @@
 
             // Set up listener for device changes
             // TODO: integrate with MediaTransferManager?
-            mLocalMediaManager = new LocalMediaManager(mContext, null, null);
+            InfoMediaManager imm =
+                    new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
+            mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm, null);
             mLocalMediaManager.startScan();
             mDevice = mLocalMediaManager.getCurrentConnectedDevice();
             mLocalMediaManager.registerCallback(mDeviceCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 3da767e..6654b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -26,6 +27,7 @@
 import android.view.View;
 import android.widget.LinearLayout;
 
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -77,10 +79,11 @@
             BroadcastDispatcher broadcastDispatcher,
             QSLogger qsLogger,
             NotificationMediaManager notificationMediaManager,
-            @Background Executor backgroundExecutor
+            @Background Executor backgroundExecutor,
+            @Nullable LocalBluetoothManager localBluetoothManager
     ) {
         super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, notificationMediaManager,
-                backgroundExecutor);
+                backgroundExecutor, localBluetoothManager);
         if (mFooter != null) {
             removeView(mFooter.getView());
         }
@@ -155,8 +158,6 @@
         Dependency.get(TunerService.class).removeTunable(mNumTiles);
     }
 
-
-
     @Override
     protected String getDumpableTag() {
         return TAG;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index ea5ec05..d7eab3a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -31,7 +31,6 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.provider.Settings;
-import android.util.Log;
 import android.util.Slog;
 import android.view.IWindowContainer;
 import android.view.LayoutInflater;
@@ -73,7 +72,7 @@
         DisplayController.OnDisplaysChangedListener {
     private static final String TAG = "Divider";
 
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     static final int DEFAULT_APP_TRANSITION_DURATION = 336;
     static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
@@ -173,6 +172,9 @@
         @Nullable
         private ValueAnimator mAnimation = null;
 
+        private boolean mPaused = true;
+        private boolean mPausedTargetAdjusted = false;
+
         private boolean getSecondaryHasFocus(int displayId) {
             try {
                 IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
@@ -185,6 +187,14 @@
             return false;
         }
 
+        private void updateDimTargets() {
+            final boolean splitIsVisible = !mView.isHidden();
+            mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
+                    ? ADJUSTED_NONFOCUS_DIM : 0.f;
+            mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible)
+                    ? ADJUSTED_NONFOCUS_DIM : 0.f;
+        }
+
         @Override
         public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
                 boolean imeShouldShow, SurfaceControl.Transaction t) {
@@ -193,18 +203,31 @@
             }
             final boolean splitIsVisible = !mView.isHidden();
             mSecondaryHasFocus = getSecondaryHasFocus(displayId);
-            mTargetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
+            final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
                     && !mSplitLayout.mDisplayLayout.isLandscape();
             mHiddenTop = hiddenTop;
             mShownTop = shownTop;
             mTargetShown = imeShouldShow;
             if (mLastAdjustTop < 0) {
                 mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
+            } else {
+                // Check for an "interruption" of an existing animation. In this case, we need to
+                // fake-flip the last-known state direction so that the animation completes in the
+                // other direction.
+                if (mTargetAdjusted != targetAdjusted && targetAdjusted == mAdjusted) {
+                    if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
+                        mAdjusted = mTargetAdjusted;
+                    }
+                }
             }
-            mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
-                    ? ADJUSTED_NONFOCUS_DIM : 0.f;
-            mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible)
-                    ? ADJUSTED_NONFOCUS_DIM : 0.f;
+            if (mPaused) {
+                mPausedTargetAdjusted = targetAdjusted;
+                if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState());
+                return;
+            }
+            mTargetAdjusted = targetAdjusted;
+            updateDimTargets();
+            if (DEBUG) Slog.d(TAG, " ime starting. vis:" + splitIsVisible + "  " + dumpState());
             if (mAnimation != null || (mImeWasShown && imeShouldShow
                     && mTargetAdjusted != mAdjusted)) {
                 // We need to animate adjustment independently of the IME position, so
@@ -259,7 +282,7 @@
         @Override
         public void onImePositionChanged(int displayId, int imeTop,
                 SurfaceControl.Transaction t) {
-            if (mAnimation != null || !inSplitMode()) {
+            if (mAnimation != null || !inSplitMode() || mPaused) {
                 // Not synchronized with IME anymore, so return.
                 return;
             }
@@ -271,7 +294,7 @@
         @Override
         public void onImeEndPositioning(int displayId, boolean cancelled,
                 SurfaceControl.Transaction t) {
-            if (mAnimation != null || !inSplitMode()) {
+            if (mAnimation != null || !inSplitMode() || mPaused) {
                 // Not synchronized with IME anymore, so return.
                 return;
             }
@@ -279,7 +302,7 @@
         }
 
         private void onProgress(float progress, SurfaceControl.Transaction t) {
-            if (mTargetAdjusted != mAdjusted) {
+            if (mTargetAdjusted != mAdjusted && !mPaused) {
                 final float fraction = mTargetAdjusted ? progress : 1.f - progress;
                 mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
                 mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
@@ -342,6 +365,52 @@
             });
             mAnimation.start();
         }
+
+        private String dumpState() {
+            return "top:" + mHiddenTop + "->" + mShownTop
+                    + " adj:" + mAdjusted + "->" + mTargetAdjusted + "(" + mLastAdjustTop + ")"
+                    + " shw:" + mImeWasShown + "->" + mTargetShown
+                    + " dims:" + mLastPrimaryDim + "," + mLastSecondaryDim
+                    + "->" + mTargetPrimaryDim + "," + mTargetSecondaryDim
+                    + " shf:" + mSecondaryHasFocus + " desync:" + (mAnimation != null)
+                    + " paus:" + mPaused + "[" + mPausedTargetAdjusted + "]";
+        }
+
+        /** Completely aborts/resets adjustment state */
+        public void pause(int displayId) {
+            if (DEBUG) Slog.d(TAG, "ime pause posting " + dumpState());
+            mHandler.post(() -> {
+                if (DEBUG) Slog.d(TAG, "ime pause run posted " + dumpState());
+                if (mPaused) {
+                    return;
+                }
+                mPaused = true;
+                mPausedTargetAdjusted = mTargetAdjusted;
+                mTargetAdjusted = false;
+                mTargetPrimaryDim = mTargetSecondaryDim = 0.f;
+                updateImeAdjustState();
+                startAsyncAnimation();
+            });
+        }
+
+        public void resume(int displayId) {
+            if (DEBUG) Slog.d(TAG, "ime resume posting " + dumpState());
+            mHandler.post(() -> {
+                if (DEBUG) Slog.d(TAG, "ime resume run posted " + dumpState());
+                if (!mPaused) {
+                    return;
+                }
+                mPaused = false;
+                mTargetAdjusted = mPausedTargetAdjusted;
+                updateDimTargets();
+                if ((mTargetAdjusted != mAdjusted) && !mMinimized && mView != null) {
+                    // End unminimize animations since they conflict with adjustment animations.
+                    mView.finishAnimations();
+                }
+                updateImeAdjustState();
+                startAsyncAnimation();
+            });
+        }
     }
     private final DividerImeController mImePositionProcessor = new DividerImeController();
 
@@ -493,6 +562,7 @@
     }
 
     void updateVisibility(final boolean visible) {
+        if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
         if (mVisible != visible) {
             mVisible = visible;
             mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
@@ -519,12 +589,21 @@
 
     /** Switch to minimized state if appropriate */
     public void setMinimized(final boolean minimized) {
+        if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
         mHandler.post(() -> {
+            if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
+            if (!mVisible) {
+                return;
+            }
             setHomeMinimized(minimized, mHomeStackResizable);
         });
     }
 
     private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
+        if (DEBUG) {
+            Slog.d(TAG, "setHomeMinimized  min:" + mMinimized + "->" + minimized + " hrsz:"
+                    + mHomeStackResizable + "->" + homeStackResizable + " split:" + inSplitMode());
+        }
         WindowContainerTransaction wct = new WindowContainerTransaction();
         // Update minimized state
         if (mMinimized != minimized) {
@@ -544,7 +623,17 @@
 
         // Sync state to DividerView if it exists.
         if (mView != null) {
+            final int displayId = mView.getDisplay() != null
+                    ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
+            // pause ime here (before updateMinimizedDockedStack)
+            if (mMinimized) {
+                mImePositionProcessor.pause(displayId);
+            }
             mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
+            if (!mMinimized) {
+                // afterwards so it can end any animations started in view
+                mImePositionProcessor.resume(displayId);
+            }
         }
         updateTouchable();
         WindowManagerProxy.applyContainerTransaction(wct);
@@ -649,7 +738,7 @@
         if (!inSplitMode()) {
             // Wasn't in split-mode yet, so enter now.
             if (DEBUG) {
-                Log.d(TAG, " entering split mode with minimized=true");
+                Slog.d(TAG, " entering split mode with minimized=true");
             }
             updateVisibility(true /* visible */);
         }
@@ -660,7 +749,7 @@
         if (!inSplitMode()) {
             // Wasn't in split-mode, so enter now.
             if (DEBUG) {
-                Log.d(TAG, " enter split mode unminimized ");
+                Slog.d(TAG, " enter split mode unminimized ");
             }
             updateVisibility(true /* visible */);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 4114bb9..131f4e1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -34,6 +34,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.Choreographer;
 import android.view.Display;
 import android.view.InsetsState;
@@ -67,12 +68,15 @@
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
+import java.util.function.Consumer;
+
 /**
  * Docked stack divider.
  */
 public class DividerView extends FrameLayout implements OnTouchListener,
         OnComputeInternalInsetsListener {
     private static final String TAG = "DividerView";
+    private static final boolean DEBUG = Divider.DEBUG;
 
     public interface DividerCallbacks {
         void onDraggingStart();
@@ -627,6 +631,7 @@
             cancelFlingAnimation();
             updateDockSide();
         }
+        if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position);
         final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(),
@@ -634,16 +639,21 @@
                         ? TASK_POSITION_SAME
                         : snapTarget.taskPosition,
                 snapTarget));
-        Runnable endAction = () -> {
+        Consumer<Boolean> endAction = cancelled -> {
+            if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
+            final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
+            // Reset minimized divider position after unminimized state animation finishes.
+            if (!cancelled && !mDockedStackMinimized && mIsInMinimizeInteraction) {
+                mIsInMinimizeInteraction = false;
+            }
             boolean dismissed = commitSnapFlags(snapTarget);
             mWindowManagerProxy.setResizing(false);
             updateDockSide();
             mCurrentAnimator = null;
             mEntranceAnimationRunning = false;
             mExitAnimationRunning = false;
-            if (!dismissed) {
-                WindowManagerProxy.applyResizeSplits((mIsInMinimizeInteraction
-                        ? mSnapTargetBeforeMinimized : snapTarget).position, mSplitLayout);
+            if (!dismissed && !wasMinimizeInteraction) {
+                WindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout);
             }
             if (mCallback != null) {
                 mCallback.onDraggingEnd();
@@ -667,12 +677,6 @@
                 }
             }
         };
-        Runnable notCancelledEndAction = () -> {
-            // Reset minimized divider position after unminimized state animation finishes
-            if (!mDockedStackMinimized && mIsInMinimizeInteraction) {
-                mIsInMinimizeInteraction = false;
-            }
-        };
         anim.addListener(new AnimatorListenerAdapter() {
 
             private boolean mCancelled;
@@ -694,15 +698,11 @@
                     delay = mSfChoreographer.getSurfaceFlingerOffsetMs();
                 }
                 if (delay == 0) {
-                    if (!mCancelled) {
-                        notCancelledEndAction.run();
-                    }
-                    endAction.run();
+                    endAction.accept(mCancelled);
                 } else {
-                    if (!mCancelled) {
-                        mHandler.postDelayed(notCancelledEndAction, delay);
-                    }
-                    mHandler.postDelayed(endAction, delay);
+                    final Boolean cancelled = mCancelled;
+                    if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms");
+                    mHandler.postDelayed(() -> endAction.accept(cancelled), delay);
                 }
             }
         });
@@ -899,6 +899,7 @@
 
     public void setMinimizedDockStack(boolean minimized, long animDuration,
             boolean isHomeStackResizable) {
+        if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized);
         mHomeStackResizable = isHomeStackResizable;
         updateDockSide();
         if (!isHomeStackResizable) {
@@ -946,6 +947,15 @@
                 .start();
     }
 
+    // Needed to end any currently playing animations when they might compete with other anims
+    // (specifically, IME adjust animation immediately after leaving minimized). Someday maybe
+    // these can be unified, but not today.
+    void finishAnimations() {
+        if (mCurrentAnimator != null) {
+            mCurrentAnimator.end();
+        }
+    }
+
     public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
         if (mAdjustedForIme == adjustedForIme) {
             return;
@@ -1061,6 +1071,11 @@
         mDividerPositionX = dockedRect.right;
         mDividerPositionY = dockedRect.bottom;
 
+        if (DEBUG) {
+            Slog.d(TAG, "Resizing split surfaces: " + dockedRect + " " + dockedTaskRect
+                    + " " + otherRect + " " + otherTaskRect);
+        }
+
         t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top);
         Rect crop = new Rect(dockedRect);
         crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index c523b7b..8669804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -40,8 +40,10 @@
 ) : Dumpable {
     private val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
     private val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius)
-    private val blurSysProp = SystemProperties
+    private val blurSupportedSysProp = SystemProperties
             .getBoolean("ro.surface_flinger.supports_background_blur", false)
+    private val blurDisabledSysProp = SystemProperties
+            .getBoolean("persist.sys.sf.disable_blurs", false)
 
     init {
         dumpManager.registerDumpable(javaClass.name, this)
@@ -97,7 +99,7 @@
      * @return {@code true} when supported.
      */
     open fun supportsBlursOnWindows(): Boolean {
-        return blurSysProp && ActivityManager.isHighEndGfx()
+        return blurSupportedSysProp && !blurDisabledSysProp && ActivityManager.isHighEndGfx()
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
@@ -106,7 +108,8 @@
             it.increaseIndent()
             it.println("minBlurRadius: $minBlurRadius")
             it.println("maxBlurRadius: $maxBlurRadius")
-            it.println("blurSysProp: $blurSysProp")
+            it.println("blurSupportedSysProp: $blurSupportedSysProp")
+            it.println("blurDisabledSysProp: $blurDisabledSysProp")
             it.println("supportsBlursOnWindows: ${supportsBlursOnWindows()}")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 3fe348f..94afde78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -262,7 +262,8 @@
 
         default void showAuthenticationDialog(Bundle bundle,
                 IBiometricServiceReceiverInternal receiver, int biometricModality,
-                boolean requireConfirmation, int userId, String opPackageName) { }
+                boolean requireConfirmation, int userId, String opPackageName,
+                long operationId) { }
         default void onBiometricAuthenticated() { }
         default void onBiometricHelp(String message) { }
         default void onBiometricError(int modality, int error, int vendorCode) { }
@@ -780,7 +781,8 @@
 
     @Override
     public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int biometricModality, boolean requireConfirmation, int userId, String opPackageName) {
+            int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
+            long operationId) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = bundle;
@@ -789,6 +791,7 @@
             args.arg3 = requireConfirmation;
             args.argi2 = userId;
             args.arg4 = opPackageName;
+            args.arg5 = operationId;
             mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
                     .sendToTarget();
         }
@@ -1164,7 +1167,8 @@
                                 someArgs.argi1 /* biometricModality */,
                                 (boolean) someArgs.arg3 /* requireConfirmation */,
                                 someArgs.argi2 /* userId */,
-                                (String) someArgs.arg4 /* opPackageName */);
+                                (String) someArgs.arg4 /* opPackageName */,
+                                (long) someArgs.arg5 /* operationId */);
                     }
                     someArgs.recycle();
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
index 18574f0..ac3523b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
@@ -32,6 +32,8 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.InfoMediaManager;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 import com.android.settingslib.media.MediaOutputSliceConstants;
@@ -106,7 +108,9 @@
     public MediaTransferManager(Context context) {
         mContext = context;
         mActivityStarter = Dependency.get(ActivityStarter.class);
-        mLocalMediaManager = new LocalMediaManager(mContext, null, null);
+        LocalBluetoothManager lbm = Dependency.get(LocalBluetoothManager.class);
+        InfoMediaManager imm = new InfoMediaManager(mContext, null, null, lbm);
+        mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, null);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index 0bfcdbd..4759d56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -182,24 +183,24 @@
 
     private void sanitizeChild(View child) {
         if (child != null) {
-            NotificationHeaderView header = (NotificationHeaderView) child.findViewById(
+            ViewGroup header = child.findViewById(
                     com.android.internal.R.id.notification_header);
             sanitizeHeader(header);
         }
     }
 
-    private void sanitizeHeader(NotificationHeaderView rowHeader) {
+    private void sanitizeHeader(ViewGroup rowHeader) {
         if (rowHeader == null) {
             return;
         }
         final int childCount = rowHeader.getChildCount();
         View time = rowHeader.findViewById(com.android.internal.R.id.time);
         boolean hasVisibleText = false;
-        for (int i = 1; i < childCount - 1 ; i++) {
+        for (int i = 0; i < childCount; i++) {
             View child = rowHeader.getChildAt(i);
             if (child instanceof TextView
                     && child.getVisibility() != View.GONE
-                    && !mDividers.contains(Integer.valueOf(child.getId()))
+                    && !mDividers.contains(child.getId())
                     && child != time) {
                 hasVisibleText = true;
                 break;
@@ -212,14 +213,14 @@
         time.setVisibility(timeVisibility);
         View left = null;
         View right;
-        for (int i = 1; i < childCount - 1 ; i++) {
+        for (int i = 0; i < childCount; i++) {
             View child = rowHeader.getChildAt(i);
-            if (mDividers.contains(Integer.valueOf(child.getId()))) {
+            if (mDividers.contains(child.getId())) {
                 boolean visible = false;
                 // Lets find the item to the right
-                for (i++; i < childCount - 1; i++) {
+                for (i++; i < childCount; i++) {
                     right = rowHeader.getChildAt(i);
-                    if (mDividers.contains(Integer.valueOf(right.getId()))) {
+                    if (mDividers.contains(right.getId())) {
                         // A divider was found, this needs to be hidden
                         i--;
                         break;
@@ -276,14 +277,18 @@
             if (!mApply) {
                 return;
             }
-            NotificationHeaderView header = row.getContractedNotificationHeader();
-            if (header == null) {
-                // No header found. We still consider this to be the same to avoid weird flickering
+            View contractedChild = row.getPrivateLayout().getContractedChild();
+            if (contractedChild == null) {
+                return;
+            }
+            View ownView = contractedChild.findViewById(mId);
+            if (ownView == null) {
+                // No view found. We still consider this to be the same to avoid weird flickering
                 // when for example showing an undo notification
                 return;
             }
             Object childData = mExtractor == null ? null : mExtractor.extractData(row);
-            mApply = mComparator.compare(mParentView, header.findViewById(mId),
+            mApply = mComparator.compare(mParentView, ownView,
                     mParentData, childData);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 901ed3f..eb8526d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -58,6 +58,7 @@
     }
 
     lateinit var root: View
+    private var blurRoot: View? = null
     private var keyguardAnimator: Animator? = null
     private var notificationAnimator: Animator? = null
     private var updateScheduled: Boolean = false
@@ -72,6 +73,7 @@
             return shadeBlurRadius.toFloat()
         }
     })
+    private val zoomInterpolator = Interpolators.ACCELERATE_DECELERATE
     private var shadeBlurRadius = 0
         set(value) {
             if (field == value) return
@@ -84,6 +86,7 @@
             field = value
             scheduleUpdate()
         }
+    private var globalDialogVisibility = 0f
 
     /**
      * Callback that updates the window blur value and is called only once per frame.
@@ -91,9 +94,12 @@
     private val updateBlurCallback = Choreographer.FrameCallback {
         updateScheduled = false
 
-        val blur = max(shadeBlurRadius, wakeAndUnlockBlurRadius)
-        blurUtils.applyBlur(root.viewRootImpl, blur)
-        wallpaperManager.setWallpaperZoomOut(root.windowToken, blurUtils.ratioOfBlurRadius(blur))
+        val blur = max(shadeBlurRadius,
+                max(wakeAndUnlockBlurRadius, blurUtils.blurRadiusOfRatio(globalDialogVisibility)))
+        blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
+        val rawZoom = max(blurUtils.ratioOfBlurRadius(blur), globalDialogVisibility)
+        wallpaperManager.setWallpaperZoomOut(root.windowToken,
+                zoomInterpolator.getInterpolation(rawZoom))
     }
 
     /**
@@ -162,14 +168,23 @@
         shadeSpring.animateToFinalPosition(newBlur.toFloat())
     }
 
-    private fun scheduleUpdate() {
+    private fun scheduleUpdate(viewToBlur: View? = null) {
         if (updateScheduled) {
             return
         }
         updateScheduled = true
+        blurRoot = viewToBlur
         choreographer.postFrameCallback(updateBlurCallback)
     }
 
+    fun updateGlobalDialogVisibility(visibility: Float, dialogView: View) {
+        if (visibility == globalDialogVisibility) {
+            return
+        }
+        globalDialogVisibility = visibility
+        scheduleUpdate(dialogView)
+    }
+
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
         IndentingPrintWriter(pw, "  ").let {
             it.println("StatusBarWindowBlurController:")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 7b5a70e..2a45bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -41,6 +41,7 @@
     private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view;
 
     private ArrayMap<Integer, View> mTransformedViews = new ArrayMap<>();
+    private ArraySet<Integer> mKeysTransformingToSimilar = new ArraySet<>();
     private ArrayMap<Integer, CustomTransformation> mCustomTransformations = new ArrayMap<>();
     private ValueAnimator mViewTransformationAnimation;
 
@@ -48,8 +49,22 @@
         mTransformedViews.put(key, transformedView);
     }
 
+    /**
+     * Add a view that transforms to a similar sibling, meaning that we should consider any mapping
+     * found treated as the same viewType. This is useful for imageViews, where it's hard to compare
+     * if the source images are the same when they are bitmap based.
+     *
+     * @param key The key how this is added
+     * @param transformedView the view that is added
+     */
+    public void addViewTransformingToSimilar(int key, View transformedView) {
+        addTransformedView(key, transformedView);
+        mKeysTransformingToSimilar.add(key);
+    }
+
     public void reset() {
         mTransformedViews.clear();
+        mKeysTransformingToSimilar.clear();
     }
 
     public void setCustomTransformation(CustomTransformation transformation, int viewType) {
@@ -60,7 +75,11 @@
     public TransformState getCurrentState(int fadingView) {
         View view = mTransformedViews.get(fadingView);
         if (view != null && view.getVisibility() != View.GONE) {
-            return TransformState.createFrom(view, this);
+            TransformState transformState = TransformState.createFrom(view, this);
+            if (mKeysTransformingToSimilar.contains(fadingView)) {
+                transformState.setIsSameAsAnyView(true);
+            }
+            return transformState;
         }
         return null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index b732966..9383f53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -21,9 +21,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.internal.widget.IMessagingLayout;
 import com.android.internal.widget.MessagingGroup;
 import com.android.internal.widget.MessagingImageMessage;
-import com.android.internal.widget.MessagingLayout;
 import com.android.internal.widget.MessagingLinearLayout;
 import com.android.internal.widget.MessagingMessage;
 import com.android.internal.widget.MessagingPropertyAnimator;
@@ -41,7 +41,7 @@
     private static Pools.SimplePool<MessagingLayoutTransformState> sInstancePool
             = new Pools.SimplePool<>(40);
     private MessagingLinearLayout mMessageContainer;
-    private MessagingLayout mMessagingLayout;
+    private IMessagingLayout mMessagingLayout;
     private HashMap<MessagingGroup, MessagingGroup> mGroupMap = new HashMap<>();
     private float mRelativeTranslationOffset;
 
@@ -266,8 +266,9 @@
             transformView(transformationAmount, to, child, otherChild, false, /* sameAsAny */
                     useLinearTransformation);
             boolean otherIsIsolated = otherGroup.getIsolatedMessage() == otherChild;
-            if (transformationAmount == 0.0f && otherIsIsolated) {
-                ownGroup.setTransformingImages(true);
+            if (transformationAmount == 0.0f
+                    && (otherIsIsolated || otherGroup.isSingleLine())) {
+                ownGroup.setClippingDisabled(true);
             }
             if (otherChild == null) {
                 child.setTranslationY(previousTranslation);
@@ -291,11 +292,20 @@
         if (useLinearTransformation) {
             ownState.setDefaultInterpolator(Interpolators.LINEAR);
         }
-        ownState.setIsSameAsAnyView(sameAsAny);
+        ownState.setIsSameAsAnyView(sameAsAny && !isGone(otherView));
         if (to) {
             if (otherView != null) {
                 TransformState otherState = TransformState.createFrom(otherView, mTransformInfo);
-                ownState.transformViewTo(otherState, transformationAmount);
+                if (!isGone(otherView)) {
+                    ownState.transformViewTo(otherState, transformationAmount);
+                } else {
+                    if (!isGone(ownView)) {
+                        ownState.disappear(transformationAmount, null);
+                    }
+                    // We still want to transform vertically if the view is gone,
+                    // since avatars serve as anchors for the rest of the layout transition
+                    ownState.transformViewVerticalTo(otherState, transformationAmount);
+                }
                 otherState.recycle();
             } else {
                 ownState.disappear(transformationAmount, null);
@@ -303,7 +313,16 @@
         } else {
             if (otherView != null) {
                 TransformState otherState = TransformState.createFrom(otherView, mTransformInfo);
-                ownState.transformViewFrom(otherState, transformationAmount);
+                if (!isGone(otherView)) {
+                    ownState.transformViewFrom(otherState, transformationAmount);
+                } else {
+                    if (!isGone(ownView)) {
+                        ownState.appear(transformationAmount, null);
+                    }
+                    // We still want to transform vertically if the view is gone,
+                    // since avatars serve as anchors for the rest of the layout transition
+                    ownState.transformViewVerticalFrom(otherState, transformationAmount);
+                }
                 otherState.recycle();
             } else {
                 ownState.appear(transformationAmount, null);
@@ -337,6 +356,9 @@
     }
 
     private boolean isGone(View view) {
+        if (view == null) {
+            return true;
+        }
         if (view.getVisibility() == View.GONE) {
             return true;
         }
@@ -408,7 +430,7 @@
                 ownGroup.getMessageContainer().setTranslationY(0);
                 ownGroup.getSenderView().setTranslationY(0);
             }
-            ownGroup.setTransformingImages(false);
+            ownGroup.setClippingDisabled(false);
             ownGroup.updateClipRect();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9a4e789..f61fe98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -31,7 +31,6 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Notification;
 import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.pm.PackageInfo;
@@ -151,7 +150,6 @@
     private int mNotificationMinHeight;
     private int mNotificationMinHeightLarge;
     private int mNotificationMinHeightMedia;
-    private int mNotificationMinHeightMessaging;
     private int mNotificationMaxHeight;
     private int mIncreasedPaddingBetweenElements;
     private int mNotificationLaunchHeight;
@@ -640,16 +638,10 @@
                 && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
         boolean showCompactMediaSeekbar = mMediaManager.getShowCompactMediaSeekbar();
 
-        Class<? extends Notification.Style> style =
-                mEntry.getSbn().getNotification().getNotificationStyle();
-        boolean isMessagingLayout = Notification.MessagingStyle.class.equals(style);
-
         if (customView && beforeP && !mIsSummaryWithChildren) {
             minHeight = beforeN ? mNotificationMinHeightBeforeN : mNotificationMinHeightBeforeP;
         } else if (isMediaLayout && showCompactMediaSeekbar) {
             minHeight = mNotificationMinHeightMedia;
-        } else if (isMessagingLayout) {
-            minHeight = mNotificationMinHeightMessaging;
         } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
             minHeight = mNotificationMinHeightLarge;
         } else {
@@ -1057,19 +1049,6 @@
         return getShowingLayout().getVisibleNotificationHeader();
     }
 
-
-    /**
-     * @return the contracted notification header. This can be different from
-     * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
-     * returns the contracted version.
-     */
-    public NotificationHeaderView getContractedNotificationHeader() {
-        if (mIsSummaryWithChildren) {
-            return mChildrenContainer.getHeaderView();
-        }
-        return mPrivateLayout.getContractedNotificationHeader();
-    }
-
     public void setLongPressListener(LongPressListener longPressListener) {
         mLongPressListener = longPressListener;
     }
@@ -1654,8 +1633,6 @@
                 R.dimen.notification_min_height_increased);
         mNotificationMinHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_min_height_media);
-        mNotificationMinHeightMessaging = NotificationUtils.getFontScaledHeight(mContext,
-                R.dimen.notification_min_height_messaging);
         mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_max_height);
         mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 6dd4ff9..91cf285 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -25,6 +25,8 @@
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
 import android.os.AsyncTask;
 import android.os.CancellationSignal;
 import android.service.notification.StatusBarNotification;
@@ -716,6 +718,10 @@
                         sbn.getNotification());
 
                 Context packageContext = sbn.getPackageContext(mContext);
+                if (recoveredBuilder.usesTemplate()) {
+                    // For all of our templates, we want it to be RTL
+                    packageContext = new RtlEnabledContext(packageContext);
+                }
                 Notification notification = sbn.getNotification();
                 if (notification.isMediaNotification()) {
                     MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
@@ -782,6 +788,19 @@
             // try to purge unnecessary cached entries.
             mRow.getImageResolver().purgeCache();
         }
+
+        private class RtlEnabledContext extends ContextWrapper {
+            private RtlEnabledContext(Context packageContext) {
+                super(packageContext);
+            }
+
+            @Override
+            public ApplicationInfo getApplicationInfo() {
+                ApplicationInfo applicationInfo = super.getApplicationInfo();
+                applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
+                return applicationInfo;
+            }
+        }
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 27fd1b2..8b8a901 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1492,13 +1492,6 @@
         }
     }
 
-    public NotificationHeaderView getContractedNotificationHeader() {
-        if (mContractedChild != null) {
-            return mContractedWrapper.getNotificationHeader();
-        }
-        return null;
-    }
-
     public NotificationHeaderView getVisibleNotificationHeader() {
         NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
         return wrapper == null ? null : wrapper.getNotificationHeader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
new file mode 100644
index 0000000..1e2571b5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.row.wrapper
+
+import android.content.Context
+import android.view.View
+
+import com.android.internal.widget.ConversationLayout
+import com.android.internal.widget.MessagingLinearLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+
+/**
+ * Wraps a notification containing a converation template
+ */
+class NotificationConversationTemplateViewWrapper constructor(
+    ctx: Context,
+    view: View,
+    row: ExpandableNotificationRow
+)
+    : NotificationTemplateViewWrapper(ctx, view, row) {
+
+    private val minHeightWithActions: Int
+    private val conversationLayout: ConversationLayout
+    private var conversationIcon: View? = null
+    private var conversationBadge: View? = null
+    private var expandButton: View? = null
+    private var messagingLinearLayout: MessagingLinearLayout? = null
+
+    init {
+        conversationLayout = view as ConversationLayout
+        minHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
+                R.dimen.notification_messaging_actions_min_height)
+    }
+
+    private fun resolveViews() {
+        messagingLinearLayout = conversationLayout.messagingLinearLayout
+        conversationIcon = conversationLayout.requireViewById(
+                com.android.internal.R.id.conversation_icon)
+        conversationBadge = conversationLayout.requireViewById(
+                com.android.internal.R.id.conversation_icon_badge)
+        expandButton = conversationLayout.requireViewById(
+                com.android.internal.R.id.expand_button)
+    }
+
+    override fun onContentUpdated(row: ExpandableNotificationRow) {
+        // Reinspect the notification. Before the super call, because the super call also updates
+        // the transformation types and we need to have our values set by then.
+        resolveViews()
+        super.onContentUpdated(row)
+    }
+
+    override fun updateTransformedTypes() {
+        // This also clears the existing types
+        super.updateTransformedTypes()
+        messagingLinearLayout?.let {
+            mTransformationHelper.addTransformedView(it.id, it)
+        }
+        conversationIcon?.let {
+            mTransformationHelper.addViewTransformingToSimilar(it.id, it)
+        }
+        conversationBadge?.let {
+            mTransformationHelper.addViewTransformingToSimilar(it.id, it)
+        }
+        expandButton?.let {
+            mTransformationHelper.addViewTransformingToSimilar(it.id, it)
+        }
+    }
+
+    override fun setRemoteInputVisible(visible: Boolean) {
+        conversationLayout.showHistoricMessages(visible)
+    }
+
+    override fun updateExpandability(expandable: Boolean, onClickListener: View.OnClickListener?) {
+        conversationLayout.updateExpandability(expandable, onClickListener)
+    }
+
+    override fun getMinLayoutHeight(): Int {
+        if (mActionsContainer != null && mActionsContainer.visibility != View.GONE) {
+            return minHeightWithActions
+        } else {
+            return super.getMinLayoutHeight()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 5e52c0a..1d06198 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -53,12 +53,13 @@
     protected final ViewTransformationHelper mTransformationHelper;
 
     protected int mColor;
-    private ImageView mIcon;
 
+    private ImageView mIcon;
     private NotificationExpandButton mExpandButton;
     protected NotificationHeaderView mNotificationHeader;
     private TextView mHeaderText;
     private ImageView mWorkProfileImage;
+
     private boolean mIsLowPriority;
     private boolean mTransformLowPriorityTitle;
     private boolean mShowExpandButtonAtEnd;
@@ -105,12 +106,16 @@
         mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
         mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
         mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
-        mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd);
-        mColor = mNotificationHeader.getOriginalIconColor();
+        if (mNotificationHeader != null) {
+            mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd);
+            mColor = mNotificationHeader.getOriginalIconColor();
+        }
     }
 
     private void addAppOpsOnClickListener(ExpandableNotificationRow row) {
-        mNotificationHeader.setAppOpsOnClickListener(row.getAppOpsOnClickListener());
+        if (mNotificationHeader != null) {
+            mNotificationHeader.setAppOpsOnClickListener(row.getAppOpsOnClickListener());
+        }
     }
 
     @Override
@@ -127,9 +132,11 @@
         updateCropToPaddingForImageViews();
         Notification notification = row.getEntry().getSbn().getNotification();
         mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
-        // The work profile image is always the same lets just set the icon tag for it not to
-        // animate
-        mWorkProfileImage.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
+        if (mWorkProfileImage != null) {
+            // The work profile image is always the same lets just set the icon tag for it not to
+            // animate
+            mWorkProfileImage.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
+        }
 
         // We need to reset all views that are no longer transforming in case a view was previously
         // transformed, but now we decided to transform its container instead.
@@ -174,8 +181,9 @@
 
     protected void updateTransformedTypes() {
         mTransformationHelper.reset();
-        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON, mIcon);
-        if (mIsLowPriority) {
+        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON,
+                mIcon);
+        if (mIsLowPriority && mHeaderText != null) {
             mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
                     mHeaderText);
         }
@@ -184,7 +192,9 @@
     @Override
     public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
         mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
-        mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
+        if (mNotificationHeader != null) {
+            mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index 0a1a2fe..d41f5af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -353,8 +353,12 @@
     @Override
     public void setHeaderVisibleAmount(float headerVisibleAmount) {
         super.setHeaderVisibleAmount(headerVisibleAmount);
-        mNotificationHeader.setAlpha(headerVisibleAmount);
-        mHeaderTranslation = (1.0f - headerVisibleAmount) * mFullHeaderTranslation;
+        float headerTranslation = 0f;
+        if (mNotificationHeader != null) {
+            mNotificationHeader.setAlpha(headerVisibleAmount);
+            headerTranslation = (1.0f - headerVisibleAmount) * mFullHeaderTranslation;
+        }
+        mHeaderTranslation = headerTranslation;
         mView.setTranslationY(mHeaderTranslation);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index c2eff8a..c834e4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -35,6 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.ContrastColorUtil;
+import com.android.internal.widget.ConversationLayout;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.notification.TransformState;
@@ -61,6 +62,9 @@
                 return new NotificationMediaTemplateViewWrapper(ctx, v, row);
             } else if ("messaging".equals(v.getTag())) {
                 return new NotificationMessagingTemplateViewWrapper(ctx, v, row);
+            } else if ("conversation".equals(v.getTag())) {
+                return new NotificationConversationTemplateViewWrapper(ctx, (ConversationLayout) v,
+                        row);
             }
             Class<? extends Notification.Style> style =
                     row.getEntry().getSbn().getNotification().getNotificationStyle();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 745843d..adca10f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -44,6 +44,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.policy.GestureNavigationSettingsObserver;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.bubbles.BubbleController;
@@ -99,8 +100,10 @@
     private final Region mExcludeRegion = new Region();
     private final Region mUnrestrictedExcludeRegion = new Region();
 
-    // The edge width where touch down is allowed
-    private int mEdgeWidth;
+    // The left side edge width where touch down is allowed
+    private int mEdgeWidthLeft;
+    // The right side edge width where touch down is allowed
+    private int mEdgeWidthRight;
     // The bottom gesture area height
     private int mBottomGestureHeight;
     // The slop to distinguish between horizontal and vertical motion
@@ -127,6 +130,8 @@
     private int mRightInset;
     private int mSysUiFlags;
 
+    private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+
     private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
             new NavigationEdgeBackPlugin.BackCallback() {
                 @Override
@@ -174,13 +179,17 @@
         mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
                 ViewConfiguration.getLongPressTimeout());
 
+        mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(
+                mContext.getMainThreadHandler(), mContext, () -> updateCurrentUserResources(res));
+
         updateCurrentUserResources(res);
         sysUiFlagContainer.addCallback(sysUiFlags -> mSysUiFlags = sysUiFlags);
     }
 
     public void updateCurrentUserResources(Resources res) {
-        mEdgeWidth = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_backGestureInset);
+        mEdgeWidthLeft = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
+        mEdgeWidthRight = mGestureNavigationSettingsObserver.getRightSensitivity(res);
+
         mBottomGestureHeight = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.navigation_bar_gesture_height);
     }
@@ -236,6 +245,7 @@
         }
 
         if (!mIsEnabled) {
+            mGestureNavigationSettingsObserver.unregister();
             mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
             mPluginManager.removePluginListener(this);
 
@@ -248,6 +258,7 @@
             }
 
         } else {
+            mGestureNavigationSettingsObserver.register();
             updateDisplaySize();
             mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
                     mContext.getMainThreadHandler());
@@ -321,7 +332,8 @@
 
     private boolean isWithinTouchRegion(int x, int y) {
         // Disallow if too far from the edge
-        if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {
+        if (x > mEdgeWidthLeft + mLeftInset
+                && x < (mDisplaySize.x - mEdgeWidthRight - mRightInset)) {
             return false;
         }
 
@@ -364,7 +376,7 @@
         if (action == MotionEvent.ACTION_DOWN) {
             // Verify if this is in within the touch region and we aren't in immersive mode, and
             // either the bouncer is showing or the notification panel is hidden
-            mIsOnLeftEdge = ev.getX() <= mEdgeWidth + mLeftInset;
+            mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
             mInRejectedExclusion = false;
             mAllowGesture = !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
                     && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
@@ -461,7 +473,8 @@
         pw.println("  mExcludeRegion=" + mExcludeRegion);
         pw.println("  mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
         pw.println("  mIsAttached=" + mIsAttached);
-        pw.println("  mEdgeWidth=" + mEdgeWidth);
+        pw.println("  mEdgeWidthLeft=" + mEdgeWidthLeft);
+        pw.println("  mEdgeWidthRight=" + mEdgeWidthRight);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index ee31300..90bc075b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -492,7 +492,7 @@
                     try {
                         result = ActivityTaskManager.getService().startActivityAsUser(
                                 null, getContext().getBasePackageName(),
-                                getContext().getFeatureId(), intent,
+                                getContext().getAttributionTag(), intent,
                                 intent.resolveTypeIfNeeded(getContext().getContentResolver()),
                                 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, o.toBundle(),
                                 UserHandle.CURRENT.getIdentifier());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index b119f0b..31266db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -551,14 +551,15 @@
     public void setWindowState(
             int displayId, @WindowType int window, @WindowVisibleState int state) {
         if (displayId == mDisplayId
-                && mNavigationBarView != null
                 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
                 && mNavigationBarWindowState != state) {
             mNavigationBarWindowState = state;
+            updateSystemUiStateFlags(-1);
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
 
-            updateSystemUiStateFlags(-1);
-            mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+            if (mNavigationBarView != null) {
+                mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+            }
         }
     }
 
@@ -1219,6 +1220,7 @@
             @Override
             public void onViewDetachedFromWindow(View v) {
                 FragmentHostManager.removeAndDestroy(v);
+                navigationBarView.removeOnAttachStateChangeListener(this);
             }
         });
         context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 43ac4cf..d24ccf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
+import android.content.om.OverlayInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ApkAssets;
 import android.os.PatternMatcher;
@@ -172,6 +173,9 @@
     public void updateCurrentInteractionMode(boolean notify) {
         mCurrentUserContext = getCurrentUserContext();
         int mode = getCurrentInteractionMode(mCurrentUserContext);
+        if (mode == NAV_BAR_MODE_GESTURAL) {
+            switchToDefaultGestureNavOverlayIfNecessary();
+        }
         mUiBgExecutor.execute(() -> {
             Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
                     Secure.NAVIGATION_MODE, String.valueOf(mode));
@@ -277,6 +281,34 @@
         }
     }
 
+    private void switchToDefaultGestureNavOverlayIfNecessary() {
+        final int userId = mCurrentUserContext.getUserId();
+        try {
+            final IOverlayManager om = mOverlayManager;
+            final OverlayInfo info = om.getOverlayInfo(NAV_BAR_MODE_GESTURAL_OVERLAY, userId);
+            if (info != null && !info.isEnabled()) {
+                // Enable the default gesture nav overlay, and move the back gesture inset scale to
+                // Settings.Secure for left and right sensitivity.
+                final int curInset = mCurrentUserContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.config_backGestureInset);
+                om.setEnabledExclusiveInCategory(NAV_BAR_MODE_GESTURAL_OVERLAY, userId);
+                final int defInset = mCurrentUserContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.config_backGestureInset);
+
+                final float scale = defInset == 0 ? 1.0f : ((float) curInset) / defInset;
+                Settings.Secure.putFloat(mCurrentUserContext.getContentResolver(),
+                        Secure.BACK_GESTURE_INSET_SCALE_LEFT, scale);
+                Settings.Secure.putFloat(mCurrentUserContext.getContentResolver(),
+                        Secure.BACK_GESTURE_INSET_SCALE_RIGHT, scale);
+                if (DEBUG) {
+                    Log.v(TAG, "Moved back sensitivity for user " + userId + " to scale " + scale);
+                }
+            }
+        } catch (SecurityException | IllegalStateException | RemoteException e) {
+            Log.e(TAG, "Failed to switch to default gesture nav overlay for user " + userId);
+        }
+    }
+
     public void setModeOverlay(String overlayPkg, int userId) {
         mUiBgExecutor.execute(() -> {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
deleted file mode 100644
index 5d8044f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.annotation.IntDef;
-import android.content.ComponentCallbacks;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.Point;
-import android.net.Uri;
-import android.os.Handler;
-import android.provider.Settings;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Coordinates with the prototype settings plugin app that uses Settings.Global to allow different
- * prototypes to run in the system. The class will handle communication changes from the settings
- * app and call back to listeners.
- */
-public class NavigationPrototypeController extends ContentObserver implements ComponentCallbacks {
-    private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
-    private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
-    private static final String PROTOTYPE_ENABLED = "prototype_enabled";
-
-    public static final String EDGE_SENSITIVITY_WIDTH_SETTING =
-            "quickstepcontroller_edge_width_sensitivity";
-    private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
-    public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
-    public static final String SHOW_HOME_HANDLE_SETTING = "quickstepcontroller_showhandle";
-    public static final String ENABLE_ASSISTANT_GESTURE = "ENABLE_ASSISTANT_GESTURE";
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
-            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
-    @interface GestureAction {}
-    static final int ACTION_DEFAULT = 0;
-    static final int ACTION_QUICKSTEP = 1;
-    static final int ACTION_QUICKSCRUB = 2;
-    static final int ACTION_BACK = 3;
-    static final int ACTION_QUICKSWITCH = 4;
-    static final int ACTION_NOTHING = 5;
-    static final int ACTION_ASSISTANT = 6;
-
-    private OnPrototypeChangedListener mListener;
-
-    /**
-     * Each index corresponds to a different action set in QuickStepController
-     * {@see updateSwipeLTRBackSetting}
-     */
-    private int[] mActionMap = new int[6];
-
-    private final Context mContext;
-
-    public NavigationPrototypeController(Context context) {
-        super(new Handler());
-        mContext = context;
-        updateSwipeLTRBackSetting();
-    }
-
-    public void setOnPrototypeChangedListener(OnPrototypeChangedListener listener) {
-        mListener = listener;
-    }
-
-    /**
-     * Observe all the settings to react to from prototype settings
-     */
-    public void register() {
-        registerObserver(HIDE_BACK_BUTTON_SETTING);
-        registerObserver(HIDE_HOME_BUTTON_SETTING);
-        registerObserver(GESTURE_MATCH_SETTING);
-        registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
-        registerObserver(SHOW_HOME_HANDLE_SETTING);
-        registerObserver(ENABLE_ASSISTANT_GESTURE);
-        mContext.registerComponentCallbacks(this);
-    }
-
-    /**
-     * Disable observing settings to react to from prototype settings
-     */
-    public void unregister() {
-        mContext.getContentResolver().unregisterContentObserver(this);
-        mContext.unregisterComponentCallbacks(this);
-    }
-
-    @Override
-    public void onChange(boolean selfChange, Uri uri) {
-        super.onChange(selfChange, uri);
-        if (!selfChange && mListener != null) {
-            final String path = uri.getPath();
-            if (path.endsWith(GESTURE_MATCH_SETTING)) {
-                // Get the settings gesture map corresponding to each action
-                // {@see updateSwipeLTRBackSetting}
-                updateSwipeLTRBackSetting();
-                mListener.onGestureRemap(mActionMap);
-            } else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
-                mListener.onBackButtonVisibilityChanged(
-                        !getGlobalBool(HIDE_BACK_BUTTON_SETTING, false));
-            } else if (path.endsWith(HIDE_HOME_BUTTON_SETTING)) {
-                mListener.onHomeButtonVisibilityChanged(!hideHomeButton());
-            } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
-                mListener.onColorAdaptChanged(mContext.getDisplayId() == DEFAULT_DISPLAY);
-            } else if (path.endsWith(SHOW_HOME_HANDLE_SETTING)) {
-                mListener.onHomeHandleVisiblilityChanged(showHomeHandle());
-            } else if (path.endsWith(ENABLE_ASSISTANT_GESTURE)) {
-                mListener.onAssistantGestureEnabled(isAssistantGestureEnabled());
-            }
-        }
-    }
-
-    /**
-     * @return the width for edge swipe
-     */
-    public int getEdgeSensitivityWidth() {
-        return mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.config_backGestureInset);
-    }
-
-    /**
-     * @return full screen height
-     */
-    public int getEdgeSensitivityHeight() {
-        final Point size = new Point();
-        mContext.getDisplay().getRealSize(size);
-        return size.y;
-    }
-
-    public boolean isEnabled() {
-        return getGlobalBool(PROTOTYPE_ENABLED, false);
-    }
-
-    /**
-     * Retrieve the action map to apply to the quick step controller
-     * @return an action map
-     */
-    int[] getGestureActionMap() {
-        return mActionMap;
-    }
-
-    /**
-     * @return if home button should be invisible
-     */
-    boolean hideHomeButton() {
-        return getGlobalBool(HIDE_HOME_BUTTON_SETTING, false /* default */);
-    }
-
-    boolean showHomeHandle() {
-        return getGlobalBool(SHOW_HOME_HANDLE_SETTING, false /* default */);
-    }
-
-    boolean isAssistantGestureEnabled() {
-        return getGlobalBool(ENABLE_ASSISTANT_GESTURE, false /* default */);
-    }
-
-
-    /**
-     * Since Settings.Global cannot pass arrays, use a string to represent each character as a
-     * gesture map to actions corresponding to {@see GestureAction}. The number is represented as:
-     * Number: [up] [down] [left] [right]
-     */
-    private void updateSwipeLTRBackSetting() {
-        String value = Settings.Global.getString(mContext.getContentResolver(),
-                GESTURE_MATCH_SETTING);
-        if (value != null) {
-            for (int i = 0; i < mActionMap.length; ++i) {
-                mActionMap[i] = Character.getNumericValue(value.charAt(i));
-            }
-        }
-    }
-
-    private boolean getGlobalBool(String name, boolean defaultVal) {
-        return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
-    }
-
-    private int getGlobalInt(String name, int defaultVal) {
-        return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal);
-    }
-
-    private void registerObserver(String name) {
-        mContext.getContentResolver()
-                .registerContentObserver(Settings.Global.getUriFor(name), false, this);
-    }
-
-    private static int convertDpToPixel(float dp) {
-        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        if (mListener != null) {
-            mListener.onEdgeSensitivityChanged(getEdgeSensitivityWidth(),
-                    getEdgeSensitivityHeight());
-        }
-    }
-
-    @Override
-    public void onLowMemory() {
-    }
-
-    public interface OnPrototypeChangedListener {
-        void onGestureRemap(@GestureAction int[] actions);
-        void onBackButtonVisibilityChanged(boolean visible);
-        void onHomeButtonVisibilityChanged(boolean visible);
-        void onHomeHandleVisiblilityChanged(boolean visible);
-        void onColorAdaptChanged(boolean enabled);
-        void onEdgeSensitivityChanged(int width, int height);
-        void onAssistantGestureEnabled(boolean enabled);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 1359f74..e25c14c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -40,6 +40,7 @@
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.leak.RotationUtils;
 
 import java.util.Objects;
 
@@ -47,7 +48,6 @@
     private static final String TAG = "PhoneStatusBarView";
     private static final boolean DEBUG = StatusBar.DEBUG;
     private static final boolean DEBUG_GESTURES = false;
-    private static final int NO_VALUE = Integer.MIN_VALUE;
     private final CommandQueue mCommandQueue;
 
     StatusBar mBar;
@@ -64,13 +64,14 @@
         }
     };
     private DarkReceiver mBattery;
-    private int mLastOrientation;
+    private int mRotationOrientation;
     @Nullable
     private View mCenterIconSpace;
     @Nullable
     private View mCutoutSpace;
     @Nullable
     private DisplayCutout mDisplayCutout;
+    private int mStatusBarHeight;
 
     /**
      * Draw this many pixels into the left/right side of the cutout to optimally use the space
@@ -107,7 +108,7 @@
         super.onAttachedToWindow();
         // Always have Battery meters in the status bar observe the dark/light modes.
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
-        if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
+        if (updateOrientationAndCutout()) {
             updateLayoutForCutout();
         }
     }
@@ -124,7 +125,7 @@
         super.onConfigurationChanged(newConfig);
 
         // May trigger cutout space layout-ing
-        if (updateOrientationAndCutout(newConfig.orientation)) {
+        if (updateOrientationAndCutout()) {
             updateLayoutForCutout();
             requestLayout();
         }
@@ -132,7 +133,7 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        if (updateOrientationAndCutout(mLastOrientation)) {
+        if (updateOrientationAndCutout()) {
             updateLayoutForCutout();
             requestLayout();
         }
@@ -140,17 +141,14 @@
     }
 
     /**
-     *
-     * @param newOrientation may pass NO_VALUE for no change
      * @return boolean indicating if we need to update the cutout location / margins
      */
-    private boolean updateOrientationAndCutout(int newOrientation) {
+    private boolean updateOrientationAndCutout() {
         boolean changed = false;
-        if (newOrientation != NO_VALUE) {
-            if (mLastOrientation != newOrientation) {
-                changed = true;
-                mLastOrientation = newOrientation;
-            }
+        int newRotation = RotationUtils.getExactRotation(mContext);
+        if (newRotation != mRotationOrientation) {
+            changed = true;
+            mRotationOrientation = newRotation;
         }
 
         if (!Objects.equals(getRootWindowInsets().getDisplayCutout(), mDisplayCutout)) {
@@ -293,17 +291,16 @@
         final int waterfallTopInset =
                 mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
         ViewGroup.LayoutParams layoutParams = getLayoutParams();
-        layoutParams.height =
-                getResources().getDimensionPixelSize(R.dimen.status_bar_height) - waterfallTopInset;
+        mStatusBarHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_height);
+        layoutParams.height = mStatusBarHeight - waterfallTopInset;
         setLayoutParams(layoutParams);
     }
 
     private void updateLayoutForCutout() {
         updateStatusBarHeight();
-        Pair<Integer, Integer> cornerCutoutMargins =
-                StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay());
-        updateCutoutLocation(cornerCutoutMargins);
-        updateSafeInsets(cornerCutoutMargins);
+        updateCutoutLocation(StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay()));
+        updateSafeInsets(StatusBarWindowView.statusBarCornerCutoutMargins(mDisplayCutout,
+                getDisplay(), mRotationOrientation, mStatusBarHeight));
     }
 
     private void updateCutoutLocation(Pair<Integer, Integer> cornerCutoutMargins) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index d1ff32d..c590139 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -47,6 +47,7 @@
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.ViewState;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -107,21 +108,21 @@
     /**
      * Default alpha value for most scrims.
      */
-    public static final float SCRIM_ALPHA = 0.2f;
+    protected static final float KEYGUARD_SCRIM_ALPHA = 0.2f;
     /**
      * Scrim opacity when the phone is about to wake-up.
      */
     public static final float WAKE_SENSOR_SCRIM_ALPHA = 0.6f;
     /**
-     * A scrim varies its opacity based on a busyness factor, for example
-     * how many notifications are currently visible.
+     * The default scrim under the shade and dialogs.
+     * This should not be lower than 0.54, otherwise we won't pass GAR.
      */
     public static final float BUSY_SCRIM_ALPHA = 0.75f;
 
     /**
-     * The most common scrim, the one under the keyguard.
+     * Same as above, but when blur is supported.
      */
-    protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = SCRIM_ALPHA;
+    public static final float BLUR_SCRIM_ALPHA = 0.54f;
 
     static final int TAG_KEY_ANIM = R.id.scrim;
     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -146,7 +147,8 @@
     private GradientColors mColors;
     private boolean mNeedsDrawableColorUpdate;
 
-    private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
+    private float mScrimBehindAlphaKeyguard = KEYGUARD_SCRIM_ALPHA;
+    private final float mDefaultScrimAlpha;
 
     // Assuming the shade is expanded during initialization
     private float mExpansionFraction = 1f;
@@ -192,9 +194,11 @@
             AlarmManager alarmManager, KeyguardStateController keyguardStateController,
             DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
-            DockManager dockManager) {
+            DockManager dockManager, BlurUtils blurUtils) {
 
         mScrimStateListener = lightBarController::setScrimState;
+        mDefaultScrimAlpha = blurUtils.supportsBlursOnWindows()
+                ? BLUR_SCRIM_ALPHA : BUSY_SCRIM_ALPHA;
 
         mKeyguardStateController = keyguardStateController;
         mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -236,6 +240,7 @@
             states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
                     mDockManager);
             states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
+            states[i].setDefaultScrimAlpha(mDefaultScrimAlpha);
         }
 
         mScrimBehind.setDefaultFocusHighlightEnabled(false);
@@ -483,7 +488,7 @@
             // Darken scrim as you pull down the shade when unlocked
             float behindFraction = getInterpolatedFraction();
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
-            mBehindAlpha = behindFraction * BUSY_SCRIM_ALPHA;
+            mBehindAlpha = behindFraction * mDefaultScrimAlpha;
             mInFrontAlpha = 0;
         } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING) {
             // Either darken of make the scrim transparent when you
@@ -491,7 +496,7 @@
             float interpolatedFract = getInterpolatedFraction();
             float alphaBehind = mState.getBehindAlpha();
             if (mDarkenWhileDragging) {
-                mBehindAlpha = MathUtils.lerp(BUSY_SCRIM_ALPHA, alphaBehind,
+                mBehindAlpha = MathUtils.lerp(mDefaultScrimAlpha, alphaBehind,
                         interpolatedFract);
                 mInFrontAlpha = mState.getFrontAlpha();
             } else {
@@ -967,7 +972,8 @@
 
         pw.print("  mTracking=");
         pw.println(mTracking);
-
+        pw.print("  mDefaultScrimAlpha=");
+        pw.println(mDefaultScrimAlpha);
         pw.print("  mExpansionFraction=");
         pw.println(mExpansionFraction);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index c23fd0a..ade642c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -92,7 +92,7 @@
     BOUNCER {
         @Override
         public void prepare(ScrimState previousState) {
-            mBehindAlpha = ScrimController.BUSY_SCRIM_ALPHA;
+            mBehindAlpha = mDefaultScrimAlpha;
             mFrontAlpha = 0f;
             mBubbleAlpha = 0f;
         }
@@ -106,7 +106,7 @@
         public void prepare(ScrimState previousState) {
             mBehindAlpha = 0;
             mBubbleAlpha = 0f;
-            mFrontAlpha = ScrimController.BUSY_SCRIM_ALPHA;
+            mFrontAlpha = mDefaultScrimAlpha;
         }
     },
 
@@ -233,9 +233,9 @@
             mBehindTint = Color.TRANSPARENT;
             mBubbleTint = Color.TRANSPARENT;
 
-            mFrontAlpha = ScrimController.TRANSPARENT;
-            mBehindAlpha = ScrimController.BUSY_SCRIM_ALPHA;
-            mBubbleAlpha = ScrimController.BUSY_SCRIM_ALPHA;
+            mFrontAlpha = 0f;
+            mBehindAlpha = mDefaultScrimAlpha;
+            mBubbleAlpha = mDefaultScrimAlpha;
 
             mAnimationDuration = ScrimController.ANIMATION_DURATION;
             mBlankScreen = false;
@@ -255,6 +255,7 @@
     float mBubbleAlpha;
 
     float mScrimBehindAlphaKeyguard;
+    float mDefaultScrimAlpha;
     ScrimView mScrimInFront;
     ScrimView mScrimBehind;
     ScrimView mScrimForBubble;
@@ -341,6 +342,10 @@
         mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
     }
 
+    public void setDefaultScrimAlpha(float defaultScrimAlpha) {
+        mDefaultScrimAlpha = defaultScrimAlpha;
+    }
+
     public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
         mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
     }
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 e6f24c2..d343090 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2602,7 +2602,7 @@
             }
             try {
                 result = ActivityTaskManager.getService().startActivityAsUser(
-                        null, mContext.getBasePackageName(), mContext.getFeatureId(),
+                        null, mContext.getBasePackageName(), mContext.getAttributionTag(),
                         intent,
                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                         null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 22bf513..760a6d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -33,6 +33,8 @@
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
 
+import com.android.systemui.util.leak.RotationUtils;
+
 /**
  * Status bar view.
  */
@@ -52,17 +54,13 @@
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
         final Insets insets = windowInsets.getInsetsIgnoringVisibility(systemBars());
-        mLeftInset = 0;
-        mRightInset = 0;
+        mLeftInset = insets.left;
+        mRightInset = insets.right;
         mTopInset = 0;
         DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
         if (displayCutout != null) {
             mTopInset = displayCutout.getWaterfallInsets().top;
-            mLeftInset = displayCutout.getSafeInsetLeft();
-            mRightInset = displayCutout.getSafeInsetRight();
         }
-        mLeftInset = Math.max(insets.left, mLeftInset);
-        mRightInset = Math.max(insets.right, mRightInset);
         applyMargins();
         return windowInsets;
     }
@@ -100,44 +98,33 @@
             return new Pair<>(roundedCornerContentPadding, roundedCornerContentPadding);
         }
 
-        // compute the padding needed for corner cutout.
-        final int leftMargin = cutout.getSafeInsetLeft();
-        final int rightMargin = cutout.getSafeInsetRight();
+        // padding needed for corner cutout.
         int leftCornerCutoutPadding = 0;
         int rightCornerCutoutPadding = 0;
         if (cornerCutoutPadding != null) {
-            if (cornerCutoutPadding.first > leftMargin) {
-                leftCornerCutoutPadding = cornerCutoutPadding.first - leftMargin;
-            }
-            if (cornerCutoutPadding.second > rightMargin) {
-                rightCornerCutoutPadding = cornerCutoutPadding.second - rightMargin;
-            }
-        }
-
-        // compute the padding needed for rounded corner
-        int leftRoundedCornerPadding = 0;
-        int rightRoundedCornerPadding = 0;
-        if (roundedCornerContentPadding > leftMargin) {
-            leftRoundedCornerPadding = roundedCornerContentPadding - leftMargin;
-        }
-        if (roundedCornerContentPadding > rightMargin) {
-            rightRoundedCornerPadding = roundedCornerContentPadding - rightMargin;
+            leftCornerCutoutPadding = cornerCutoutPadding.first;
+            rightCornerCutoutPadding = cornerCutoutPadding.second;
         }
 
         return new Pair<>(
-                Math.max(leftCornerCutoutPadding, leftRoundedCornerPadding),
-                Math.max(rightCornerCutoutPadding, rightRoundedCornerPadding));
+                Math.max(leftCornerCutoutPadding, roundedCornerContentPadding),
+                Math.max(rightCornerCutoutPadding, roundedCornerContentPadding));
     }
 
+
     /**
-     * Compute the corner cutout margins
-     *
-     * @param cutout
-     * @param display
-     * @return
+     * Compute the corner cutout margins in portrait mode
      */
     public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout,
             Display display) {
+        return statusBarCornerCutoutMargins(cutout, display, RotationUtils.ROTATION_NONE, 0);
+    }
+
+    /**
+     * Compute the corner cutout margins in the given orientation (exactRotation)
+     */
+    public static Pair<Integer, Integer> statusBarCornerCutoutMargins(DisplayCutout cutout,
+            Display display, int exactRotation, int statusBarHeight) {
         if (cutout == null) {
             return null;
         }
@@ -145,14 +132,33 @@
         display.getRealSize(size);
 
         Rect bounds = new Rect();
-        boundsFromDirection(cutout, Gravity.TOP, bounds);
+        switch (exactRotation) {
+            case RotationUtils.ROTATION_LANDSCAPE:
+                boundsFromDirection(cutout, Gravity.LEFT, bounds);
+                break;
+            case RotationUtils.ROTATION_SEASCAPE:
+                boundsFromDirection(cutout, Gravity.RIGHT, bounds);
+                break;
+            case RotationUtils.ROTATION_NONE:
+                boundsFromDirection(cutout, Gravity.TOP, bounds);
+                break;
+            case RotationUtils.ROTATION_UPSIDE_DOWN:
+                // we assume the cutout is always on top in portrait mode
+                return null;
+        }
+
+        if (statusBarHeight >= 0 && bounds.top > statusBarHeight) {
+            return null;
+        }
 
         if (bounds.left <= 0) {
             return new Pair<>(bounds.right, 0);
         }
+
         if (bounds.right >= size.x) {
             return new Pair<>(0, size.x - bounds.left);
         }
+
         return null;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index cebcf76..54e8e72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -577,7 +577,7 @@
     }
 
     boolean isDataDisabled() {
-        return !mPhone.isDataConnectionEnabled();
+        return !mPhone.isDataConnectionAllowed();
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 2f1b160..5411839 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -49,6 +49,8 @@
 public class DisplayImeController implements DisplayController.OnDisplaysChangedListener {
     private static final String TAG = "DisplayImeController";
 
+    private static final boolean DEBUG = false;
+
     public static final int ANIMATION_DURATION_SHOW_MS = 275;
     public static final int ANIMATION_DURATION_HIDE_MS = 340;
     public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -209,6 +211,7 @@
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
+            if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
             startAnimation(true /* show */);
         }
 
@@ -217,6 +220,7 @@
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
+            if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
             startAnimation(false /* show */);
         }
 
@@ -241,6 +245,11 @@
                 return;
             }
             mHandler.post(() -> {
+                if (DEBUG) {
+                    Slog.d(TAG, "Run startAnim  show:" + show + "  was:"
+                            + (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
+                            : (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
+                }
                 if ((mAnimationDirection == DIRECTION_SHOW && show)
                         || (mAnimationDirection == DIRECTION_HIDE && !show)) {
                     return;
@@ -289,6 +298,11 @@
                     public void onAnimationStart(Animator animation) {
                         SurfaceControl.Transaction t = mTransactionPool.acquire();
                         t.setPosition(mImeSourceControl.getLeash(), x, startY);
+                        if (DEBUG) {
+                            Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
+                                    + imeTop(imeSource, hiddenY) + "->" + imeTop(imeSource, shownY)
+                                    + " showing:" + (mAnimationDirection == DIRECTION_SHOW));
+                        }
                         dispatchStartPositioning(mDisplayId, imeTop(imeSource, hiddenY),
                                 imeTop(imeSource, shownY), mAnimationDirection == DIRECTION_SHOW,
                                 t);
@@ -304,6 +318,7 @@
                     }
                     @Override
                     public void onAnimationEnd(Animator animation) {
+                        if (DEBUG) Slog.d(TAG, "onAnimationEnd " + mCancelled);
                         SurfaceControl.Transaction t = mTransactionPool.acquire();
                         if (!mCancelled) {
                             t.setPosition(mImeSourceControl.getLeash(), x, endY);
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index ccb8699..381ccdb 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -196,7 +196,7 @@
             final Display display = mDisplayController.getDisplay(mDisplayId);
             SurfaceControlViewHost viewRoot = new SurfaceControlViewHost(mContext, display, wwm);
             attrs.flags |= FLAG_HARDWARE_ACCELERATED;
-            viewRoot.addView(view, attrs);
+            viewRoot.setView(view, attrs);
             mViewRoots.put(view, viewRoot);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 1b34b3d..b6537bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -23,6 +23,8 @@
 
 import static com.android.systemui.ScreenDecorations.rectsToRegion;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -42,6 +44,7 @@
 import android.content.res.Configuration;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.graphics.drawable.VectorDrawable;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
@@ -142,6 +145,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
@@ -161,6 +166,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius, 20);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 20);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // no cutout
         doReturn(null).when(mScreenDecorations).getCutout();
@@ -182,6 +189,67 @@
     }
 
     @Test
+    public void testRoundingRadius_NoCutout() {
+        final int testRadius = 1;
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, testRadius);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius_top, testRadius);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius_bottom, testRadius);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+
+        // no cutout
+        doReturn(null).when(mScreenDecorations).getCutout();
+
+        mScreenDecorations.start();
+        // Size of corner view should same as rounded_corner_radius{_top|_bottom}
+        assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadius);
+        assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadius);
+        assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadius);
+    }
+
+    @Test
+    public void testRoundingMultipleRadius_NoCutout() {
+        final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
+        final int multipleRadiusSize = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 9999);
+        mContext.getOrCreateTestableResources()
+                .addOverride(dimen.rounded_corner_content_padding, 9999);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, true);
+
+        // no cutout
+        doReturn(null).when(mScreenDecorations).getCutout();
+
+        mScreenDecorations.start();
+        // Top and bottom windows are created for rounded corners.
+        verify(mWindowManager, times(1))
+                .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any());
+        verify(mWindowManager, times(1))
+                .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any());
+
+        // Left and right window should be null.
+        assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]);
+        assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]);
+
+        // One tunable.
+        verify(mTunerService, times(1)).addTunable(any(), any());
+
+        // Size of corner view should exactly match max(width, height) of R.drawable.rounded
+        assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize);
+        assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize);
+        assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize);
+    }
+
+    @Test
     public void testNoRounding_CutoutShortEdge() {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
@@ -193,6 +261,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // top cutout
         doReturn(new DisplayCutout(
@@ -227,6 +297,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // left cutout
         doReturn(new DisplayCutout(
@@ -257,6 +329,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius, 20);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 20);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // top cutout
         doReturn(new DisplayCutout(
@@ -288,6 +362,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius, 20);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 20);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // left cutout
         doReturn(new DisplayCutout(
@@ -319,6 +395,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius, 20);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 20);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // top and left cutout
         doReturn(new DisplayCutout(
@@ -355,6 +433,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // Set to short edge cutout(top).
         doReturn(new DisplayCutout(
@@ -402,6 +482,8 @@
                 com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         // top cutout
         doReturn(new DisplayCutout(
@@ -440,6 +522,8 @@
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.dimen.rounded_corner_radius, 20);
+        mContext.getOrCreateTestableResources()
+                .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
 
         mScreenDecorations.start();
         assertEquals(mScreenDecorations.mRoundedDefault, 20);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index c6c7b87..1db8e4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -78,7 +78,9 @@
 
         mAuthContainer.mBiometricCallback.onAction(
                 AuthBiometricView.Callback.ACTION_AUTHENTICATED);
-        verify(mCallback).onDismissed(eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED));
+        verify(mCallback).onDismissed(
+                eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
@@ -87,7 +89,9 @@
 
         mAuthContainer.mBiometricCallback.onAction(
                 AuthBiometricView.Callback.ACTION_USER_CANCELED);
-        verify(mCallback).onDismissed(eq(AuthDialogCallback.DISMISSED_USER_CANCELED));
+        verify(mCallback).onDismissed(
+                eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
@@ -96,7 +100,9 @@
 
         mAuthContainer.mBiometricCallback.onAction(
                 AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE);
-        verify(mCallback).onDismissed(eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE));
+        verify(mCallback).onDismissed(
+                eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
@@ -114,7 +120,9 @@
 
         mAuthContainer.mBiometricCallback.onAction(
                 AuthBiometricView.Callback.ACTION_ERROR);
-        verify(mCallback).onDismissed(AuthDialogCallback.DISMISSED_ERROR);
+        verify(mCallback).onDismissed(
+                eq(AuthDialogCallback.DISMISSED_ERROR),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
@@ -219,7 +227,8 @@
 
         @Override
         public void animateAway(int reason) {
-            mConfig.mCallback.onDismissed(reason);
+            // TODO: Credential attestation should be testable/tested
+            mConfig.mCallback.onDismissed(reason, null /* credentialAttestation */);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 65399bf..fc1ddf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -57,12 +57,14 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.AdditionalMatchers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Random;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -110,52 +112,75 @@
     @Test
     public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+                null /* credentialAttestation */);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE,
+                null /* credentialAttestation */);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_NEGATIVE),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE,
+                null /* credentialAttestation */);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED,
+                null /* credentialAttestation */);
         verify(mReceiver).onDialogDismissed(
-                BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED);
+                eq(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testSendsReasonError_whenDismissedByError() throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR,
+                null /* credentialAttestation */);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_ERROR),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testSendsReasonServerRequested_whenDismissedByServer() throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER,
+                null /* credentialAttestation */);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testSendsReasonCredentialConfirmed_whenDeviceCredentialAuthenticated()
             throws Exception {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED);
+
+        final byte[] credentialAttestation = generateRandomHAT();
+
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED,
+                credentialAttestation);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
+                AdditionalMatchers.aryEq(credentialAttestation));
     }
 
     // Statusbar tests
@@ -302,8 +327,13 @@
         showDialog(Authenticators.DEVICE_CREDENTIAL, BiometricPrompt.TYPE_NONE);
         verify(mDialog1).show(any(), any());
 
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED);
-        verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED);
+        final byte[] credentialAttestation = generateRandomHAT();
+
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED,
+                credentialAttestation);
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
+                AdditionalMatchers.aryEq(credentialAttestation));
 
         mAuthController.hideAuthenticationDialog();
     }
@@ -395,20 +425,24 @@
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
         verify(mDialog1).dismissWithoutCallback(true /* animate */);
-        verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL));
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
+                eq(null) /* credentialAttestation */);
     }
 
     @Test
     public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+                null /* credentialAttestation */);
         mAuthController.onTryAgainPressed();
     }
 
     @Test
     public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() {
         showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
-        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+                null /* credentialAttestation */);
         mAuthController.onDeviceCredentialPressed();
     }
 
@@ -422,7 +456,9 @@
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
         verify(mDialog1).dismissWithoutCallback(true /* animate */);
-        verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL));
+        verify(mReceiver).onDialogDismissed(
+                eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
+                eq(null) /* credentialAttestation */);
     }
 
     // Helpers
@@ -433,7 +469,8 @@
                 biometricModality,
                 true /* requireConfirmation */,
                 0 /* userId */,
-                "testPackage");
+                "testPackage",
+                0 /* operationId */);
     }
 
     private Bundle createTestDialogBundle(int authenticators) {
@@ -453,6 +490,13 @@
         return bundle;
     }
 
+    private byte[] generateRandomHAT() {
+        byte[] HAT = new byte[69];
+        Random random = new Random();
+        random.nextBytes(HAT);
+        return HAT;
+    }
+
     private final class TestableAuthController extends AuthController {
         private int mBuildCount = 0;
         private Bundle mLastBiometricPromptBundle;
@@ -464,7 +508,7 @@
         @Override
         protected AuthDialog buildDialog(Bundle biometricPromptBundle,
                 boolean requireConfirmation, int userId, int type, String opPackageName,
-                boolean skipIntro) {
+                boolean skipIntro, long operationId) {
 
             mLastBiometricPromptBundle = biometricPromptBundle;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index f40fc94..866dfdc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -268,13 +268,18 @@
         sendUpdatedEntryAtTime(mEntryB2, 5000);
         mBubbleData.setListener(mListener);
 
-        // Test
         sendUpdatedEntryAtTime(mEntryC1, 6000);
         verifyUpdateReceived();
-
-        // Verify
         assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED);
-        assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(mBubbleA1));
+        assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
+
+        Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1);
+        bubbleA1.markUpdatedAt(7000L);
+        mBubbleData.notificationEntryUpdated(bubbleA1, false /* suppressFlyout*/,
+                true /* showInShade */);
+        verifyUpdateReceived();
+        assertBubbleRemoved(mBubbleA2, BubbleController.DISMISS_AGED);
+        assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
     }
 
     /**
@@ -931,6 +936,11 @@
         assertThat(update.expanded).named("expanded").isEqualTo(expected);
     }
 
+    private void assertOverflowChangedTo(ImmutableList<Bubble> bubbles) {
+        BubbleData.Update update = mUpdateCaptor.getValue();
+        assertThat(update.overflowBubbles).isEqualTo(bubbles);
+    }
+
 
     private NotificationEntry createBubbleEntry(int userId, String notifKey, String packageName) {
         return createBubbleEntry(userId, notifKey, packageName, 1000);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index e3187cb9..b1ac022 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -43,6 +43,7 @@
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.IntSupplier;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -59,7 +60,13 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        mStackController = spy(new TestableStackController(mFloatingContentCoordinator));
+        mStackController = spy(new TestableStackController(
+                mFloatingContentCoordinator, new IntSupplier() {
+                    @Override
+                    public int getAsInt() {
+                        return mLayout.getChildCount();
+                    }
+                }));
         mLayout.setActiveController(mStackController);
         addOneMoreThanBubbleLimitBubbles();
         mStackOffset = mLayout.getResources().getDimensionPixelSize(R.dimen.bubble_stack_offset);
@@ -295,8 +302,9 @@
      */
     private class TestableStackController extends StackAnimationController {
         TestableStackController(
-                FloatingContentCoordinator floatingContentCoordinator) {
-            super(floatingContentCoordinator);
+                FloatingContentCoordinator floatingContentCoordinator,
+                IntSupplier bubbleCountSupplier) {
+            super(floatingContentCoordinator, bubbleCountSupplier);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 9117ea8..f535351 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -248,31 +248,6 @@
     }
 
     @Test
-    public void pausingAod_softBlanks_withSpuriousSensorDuringPause() throws Exception {
-        mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
-        mScreen.transitionTo(INITIALIZED, DOZE_AOD);
-        mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING);
-        mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED);
-
-        reset(mDozeHost);
-        mSensor.sendSensorEvent(1);
-        verify(mDozeHost).setAodDimmingScrim(eq(1f));
-    }
-
-    @Test
-    public void screenOff_softBlanks() throws Exception {
-        mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
-        mScreen.transitionTo(INITIALIZED, DOZE_AOD);
-        mScreen.transitionTo(DOZE_AOD, DOZE);
-        verify(mDozeHost).setAodDimmingScrim(eq(1f));
-
-        reset(mDozeHost);
-        mScreen.transitionTo(DOZE, DOZE_AOD);
-        mSensor.sendSensorEvent(2);
-        verify(mDozeHost).setAodDimmingScrim(eq(0f));
-    }
-
-    @Test
     public void pausingAod_unblanksAfterSensor() throws Exception {
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 8320b05..6871aad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -42,6 +42,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.phone.NavigationModeController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.util.DeviceConfigProxy;
@@ -71,6 +72,7 @@
     private @Mock DumpManager mDumpManager;
     private @Mock PowerManager mPowerManager;
     private @Mock TrustManager mTrustManager;
+    private @Mock NavigationModeController mNavigationModeController;
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
@@ -88,7 +90,7 @@
                 mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
                 mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager,
                 mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
-                mPowerManager, mTrustManager, mDeviceConfig);
+                mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController);
         mViewMediator.start();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index a2ab784..b863f14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -58,7 +58,8 @@
 
     @Before
     public void setUp() throws Exception {
-        mPipAnimationController = new PipAnimationController(mContext);
+        mPipAnimationController = new PipAnimationController(
+                mContext, new PipSurfaceTransactionHelper(mContext));
         MockitoAnnotations.initMocks(this);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
index b12db2b..0bf0f04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
@@ -24,6 +24,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableResources;
+import android.util.Size;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 
@@ -51,6 +52,7 @@
     private static final float MIN_ASPECT_RATIO = 0.5f;
     private static final float MAX_ASPECT_RATIO = 2f;
     private static final Rect EMPTY_CURRENT_BOUNDS = null;
+    private static final Size EMPTY_MINIMAL_SIZE = null;
 
     private PipBoundsHandler mPipBoundsHandler;
     private DisplayInfo mDefaultDisplayInfo;
@@ -119,7 +121,7 @@
         };
         for (float aspectRatio : aspectRatios) {
             final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                    aspectRatio, EMPTY_CURRENT_BOUNDS);
+                    aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
             final float actualAspectRatio =
                     destinationBounds.width() / (destinationBounds.height() * 1f);
             assertEquals("Destination bounds matches the given aspect ratio",
@@ -135,7 +137,7 @@
         };
         for (float aspectRatio : invalidAspectRatios) {
             final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                    aspectRatio, EMPTY_CURRENT_BOUNDS);
+                    aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
             final float actualAspectRatio =
                     destinationBounds.width() / (destinationBounds.height() * 1f);
             assertEquals("Destination bounds fallbacks to default aspect ratio",
@@ -151,7 +153,7 @@
         currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left;
 
         final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                aspectRatio, currentBounds);
+                aspectRatio, currentBounds, EMPTY_MINIMAL_SIZE);
 
         final float actualAspectRatio =
                 destinationBounds.width() / (destinationBounds.height() * 1f);
@@ -160,14 +162,58 @@
     }
 
     @Test
+    public void getDestinationBounds_withMinSize_returnMinBounds() {
+        final float[] aspectRatios = new float[] {
+                (MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2,
+                DEFAULT_ASPECT_RATIO,
+                (MAX_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2
+        };
+        final Size[] minimalSizes = new Size[] {
+                new Size((int) (100 * aspectRatios[0]), 100),
+                new Size((int) (100 * aspectRatios[1]), 100),
+                new Size((int) (100 * aspectRatios[2]), 100)
+        };
+        for (int i = 0; i < aspectRatios.length; i++) {
+            final float aspectRatio = aspectRatios[i];
+            final Size minimalSize = minimalSizes[i];
+            final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
+                    aspectRatio, EMPTY_CURRENT_BOUNDS, minimalSize);
+            assertTrue("Destination bounds is no smaller than minimal requirement",
+                    (destinationBounds.width() == minimalSize.getWidth()
+                            && destinationBounds.height() >= minimalSize.getHeight())
+                            || (destinationBounds.height() == minimalSize.getHeight()
+                            && destinationBounds.width() >= minimalSize.getWidth()));
+            final float actualAspectRatio =
+                    destinationBounds.width() / (destinationBounds.height() * 1f);
+            assertEquals("Destination bounds matches the given aspect ratio",
+                    aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN);
+        }
+    }
+
+    @Test
+    public void getDestinationBounds_withCurrentBounds_ignoreMinBounds() {
+        final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
+        final Rect currentBounds = new Rect(0, 0, 0, 100);
+        currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left;
+        final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2);
+
+        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
+                aspectRatio, currentBounds, minSize);
+
+        assertTrue("Destination bounds ignores minimal size",
+                destinationBounds.width() > minSize.getWidth()
+                        && destinationBounds.height() > minSize.getHeight());
+    }
+
+    @Test
     public void setShelfHeight_offsetBounds() {
         final int shelfHeight = 100;
         final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         mPipBoundsHandler.setShelfHeight(true, shelfHeight);
         final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         oldPosition.offset(0, -shelfHeight);
         assertBoundsWithMargin("offsetBounds by shelf", oldPosition, newPosition);
@@ -177,11 +223,11 @@
     public void onImeVisibilityChanged_offsetBounds() {
         final int imeHeight = 100;
         final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight);
         final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         oldPosition.offset(0, -imeHeight);
         assertBoundsWithMargin("offsetBounds by IME", oldPosition, newPosition);
@@ -191,13 +237,13 @@
     public void onSaveReentryBounds_restoreLastPosition() {
         final ComponentName componentName = new ComponentName(mContext, "component1");
         final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         oldPosition.offset(0, -100);
         mPipBoundsHandler.onSaveReentryBounds(componentName, oldPosition);
 
         final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         assertBoundsWithMargin("restoreLastPosition", oldPosition, newPosition);
     }
@@ -206,14 +252,14 @@
     public void onResetReentryBounds_useDefaultBounds() {
         final ComponentName componentName = new ComponentName(mContext, "component1");
         final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
         final Rect newBounds = new Rect(defaultBounds);
         newBounds.offset(0, -100);
         mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds);
 
         mPipBoundsHandler.onResetReentryBounds(componentName);
         final Rect actualBounds = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         assertBoundsWithMargin("useDefaultBounds", defaultBounds, actualBounds);
     }
@@ -222,14 +268,14 @@
     public void onResetReentryBounds_componentMismatch_restoreLastPosition() {
         final ComponentName componentName = new ComponentName(mContext, "component1");
         final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
         final Rect newBounds = new Rect(defaultBounds);
         newBounds.offset(0, -100);
         mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds);
 
         mPipBoundsHandler.onResetReentryBounds(new ComponentName(mContext, "component2"));
         final Rect actualBounds = mPipBoundsHandler.getDestinationBounds(
-                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS);
+                DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
 
         assertBoundsWithMargin("restoreLastPosition", newBounds, actualBounds);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index 616399a..ac30421 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -35,6 +35,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
@@ -85,6 +86,8 @@
     private NotificationMediaManager mNotificationMediaManager;
     @Mock
     private Executor mBackgroundExecutor;
+    @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
 
     @Before
     public void setup() throws Exception {
@@ -94,7 +97,8 @@
         mTestableLooper.runWithLooper(() -> {
             mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
             mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
-                    mQSLogger, mNotificationMediaManager, mBackgroundExecutor);
+                    mQSLogger, mNotificationMediaManager, mBackgroundExecutor,
+                    mLocalBluetoothManager);
             // Provides a parent with non-zero size for QSPanel
             mParentView = new FrameLayout(mContext);
             mParentView.addView(mQsPanel);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 7c6da63..cffcabb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -409,11 +409,12 @@
     public void testShowAuthenticationDialog() {
         Bundle bundle = new Bundle();
         String packageName = "test";
+        final long operationId = 1;
         mCommandQueue.showAuthenticationDialog(bundle, null /* receiver */, 1, true, 3,
-                packageName);
+                packageName, operationId);
         waitForIdleSync();
         verify(mCallbacks).showAuthenticationDialog(eq(bundle), eq(null), eq(1), eq(true), eq(3),
-                eq(packageName));
+                eq(packageName), eq(operationId));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 408dfc0..23f2637 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -50,6 +50,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -101,6 +102,8 @@
     private SysuiColorExtractor mSysuiColorExtractor;
     @Mock
     private DockManager mDockManager;
+    @Mock
+    private BlurUtils mBlurUtils;
 
 
     private static class AnimatorListener implements Animator.AnimatorListener {
@@ -215,7 +218,7 @@
         mScrimController = new ScrimController(mLightBarController,
                 mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
                 new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
-                mDockManager);
+                mDockManager, mBlurUtils);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
         mScrimController.setAnimatorListener(mAnimatorListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 831925f..cddbb9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -207,7 +207,7 @@
     protected void setupNetworkController() {
         // For now just pretend to be the data sim, so we can test that too.
         mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(true);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(true);
         setDefaultSubId(mSubId);
         setSubscriptions(mSubId);
         mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 3eb0c44..d8b6aac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -119,7 +119,7 @@
     @Test
     public void testNoInternetIcon_withDefaultSub() {
         setupNetworkController();
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
         setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -133,7 +133,7 @@
     @Test
     public void testDataDisabledIcon_withDefaultSub() {
         setupNetworkController();
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
         setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -147,7 +147,7 @@
     @Test
     public void testNonDefaultSIM_showsFullSignal_connected() {
         setupNetworkController();
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
         setupDefaultSignal();
         setDefaultSubId(mSubId + 1);
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
@@ -162,7 +162,7 @@
     @Test
     public void testNonDefaultSIM_showsFullSignal_disconnected() {
         setupNetworkController();
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
         setupDefaultSignal();
         setDefaultSubId(mSubId + 1);
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
@@ -177,7 +177,7 @@
     @Test
     public void testDataDisabledIcon_UserNotSetup() {
         setupNetworkController();
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
         setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -192,7 +192,7 @@
     @Test
     public void testAlwaysShowDataRatIcon() {
         setupDefaultSignal();
-        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+        when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
                 TelephonyManager.NETWORK_TYPE_GSM);
 
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index a18f5da..fd6f171 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -32,7 +32,7 @@
  * @hide
  */
 @SystemApi(client = MODULE_LIBRARIES)
-public class TetheringConstants {
+public final class TetheringConstants {
     /** An explicit private class to avoid exposing constructor.*/
     private TetheringConstants() { }
 
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml
index 6f692c8..b9c5f1d 100644
--- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml
@@ -16,6 +16,9 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
+    <string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
+    <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation"></string>
+
     <!-- Height of the status bar in portrait. The height should be
          Max((status bar content height + waterfall top size), top cutout size) -->
     <dimen name="status_bar_height_portrait">28dp</dimen>
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index e73f9ce..53afa6e 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -57,6 +57,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.server.autofill.ui.InlineSuggestionFactory;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.TimeUnit;
@@ -255,8 +256,12 @@
                             mCallbacks.logAugmentedAutofillSelected(sessionId,
                                     dataset.getId());
                             try {
-                                client.autofill(sessionId, dataset.getFieldIds(),
-                                        dataset.getFieldValues());
+                                final ArrayList<AutofillId> fieldIds = dataset.getFieldIds();
+                                final int size = fieldIds.size();
+                                final boolean hideHighlight = size == 1
+                                        && fieldIds.get(0).equals(focusedId);
+                                client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
+                                        hideHighlight);
                             } catch (RemoteException e) {
                                 Slog.w(TAG, "Encounter exception autofilling the values");
                             }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8265009..9693535 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3382,6 +3382,8 @@
                 final List<AutofillId> ids = new ArrayList<>(entryCount);
                 final List<AutofillValue> values = new ArrayList<>(entryCount);
                 boolean waitingDatasetAuth = false;
+                boolean hideHighlight = (entryCount == 1
+                        && dataset.getFieldIds().get(0).equals(mCurrentViewId));
                 for (int i = 0; i < entryCount; i++) {
                     if (dataset.getFieldValues().get(i) == null) {
                         continue;
@@ -3405,7 +3407,7 @@
                     }
                     if (sDebug) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
 
-                    mClient.autofill(id, ids, values);
+                    mClient.autofill(id, ids, values, hideHighlight);
                     if (dataset.getId() != null) {
                         if (mSelectedDatasetIds == null) {
                             mSelectedDatasetIds = new ArrayList<>();
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 ee59d89..0ca9dd9 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -329,8 +329,14 @@
             @NonNull Runnable onErrorCallback) {
         return new IInlineSuggestionUiCallback.Stub() {
             @Override
-            public void onAutofill() throws RemoteException {
+            public void onClick() throws RemoteException {
                 onAutofillCallback.run();
+                callback.onClick();
+            }
+
+            @Override
+            public void onLongClick() throws RemoteException {
+                callback.onLongClick();
             }
 
             @Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 942d563..9e19ad2 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,9 +98,9 @@
         "android.hardware.power-V1.0-java",
         "android.hardware.tv.cec-V1.0-java",
         "android.hardware.vibrator-java",
+        "android.net.ipsec.ike.stubs.module_libs_api",
         "app-compat-annotations",
         "framework-tethering-stubs-module_libs_api",
-        "ike-stubs",
     ],
 
     required: [
@@ -128,7 +128,6 @@
         "android.hidl.manager-V1.2-java",
         "dnsresolver_aidl_interface-V2-java",
         "netd_event_listener_interface-java",
-        "ike-stubs",
         "overlayable_policy_aidl-java",
     ],
 
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index dadcd4e..9fddafb 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -991,4 +991,9 @@
      * @param enabled true if visibility blocks should be logged
      */
     public abstract void setVisibilityLogging(String packageName, boolean enabled);
+
+    /**
+     * Returns if a package name is a valid system package.
+     */
+    public abstract boolean isSystemPackage(@NonNull String packageName);
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7287a44..3a3358c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2083,9 +2083,9 @@
     }
 
     private void enforceNetworkFactoryPermission() {
-        mContext.enforceCallingOrSelfPermission(
+        enforceAnyPermissionOf(
                 android.Manifest.permission.NETWORK_FACTORY,
-                "ConnectivityService");
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
     private boolean checkSettingsPermission() {
@@ -7803,12 +7803,15 @@
     private void handleNetworkTestedWithExtras(
             @NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) {
         final NetworkAgentInfo nai = reportEvent.mNai;
+        final NetworkCapabilities networkCapabilities =
+                new NetworkCapabilities(nai.networkCapabilities);
+        clearNetworkCapabilitiesUids(networkCapabilities);
         final ConnectivityReport report =
                 new ConnectivityReport(
                         reportEvent.mNai.network,
                         reportEvent.mTimestampMillis,
                         nai.linkProperties,
-                        nai.networkCapabilities,
+                        networkCapabilities,
                         extras);
         final List<IConnectivityDiagnosticsCallback> results =
                 getMatchingPermissionedCallbacks(nai);
@@ -7824,13 +7827,16 @@
     private void handleDataStallSuspected(
             @NonNull NetworkAgentInfo nai, long timestampMillis, int detectionMethod,
             @NonNull PersistableBundle extras) {
+        final NetworkCapabilities networkCapabilities =
+                new NetworkCapabilities(nai.networkCapabilities);
+        clearNetworkCapabilitiesUids(networkCapabilities);
         final DataStallReport report =
                 new DataStallReport(
                         nai.network,
                         timestampMillis,
                         detectionMethod,
                         nai.linkProperties,
-                        nai.networkCapabilities,
+                        networkCapabilities,
                         extras);
         final List<IConnectivityDiagnosticsCallback> results =
                 getMatchingPermissionedCallbacks(nai);
@@ -7856,6 +7862,12 @@
         }
     }
 
+    private void clearNetworkCapabilitiesUids(@NonNull NetworkCapabilities nc) {
+        nc.setUids(null);
+        nc.setAdministratorUids(Collections.EMPTY_LIST);
+        nc.setOwnerUid(Process.INVALID_UID);
+    }
+
     private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks(
             @NonNull NetworkAgentInfo nai) {
         final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>();
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 318a030..191a9bc 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -22,13 +22,9 @@
 import android.gsi.GsiProgress;
 import android.gsi.IGsiService;
 import android.gsi.IGsiServiceCallback;
-import android.gsi.IGsid;
 import android.os.Environment;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.image.IDynamicSystemService;
@@ -42,9 +38,8 @@
  * DynamicSystemService implements IDynamicSystemService. It provides permission check before
  * passing requests to gsid
  */
-public class DynamicSystemService extends IDynamicSystemService.Stub implements DeathRecipient {
+public class DynamicSystemService extends IDynamicSystemService.Stub {
     private static final String TAG = "DynamicSystemService";
-    private static final String NO_SERVICE_ERROR = "no gsiservice";
     private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
     private static final String PATH_DEFAULT = "/data/gsi/";
     private Context mContext;
@@ -55,57 +50,12 @@
         mContext = context;
     }
 
-    private static IGsiService connect(DeathRecipient recipient) throws RemoteException {
-        IBinder binder = ServiceManager.getService("gsiservice");
-        if (binder == null) {
-            return null;
-        }
-        /**
-         * The init will restart gsiservice if it crashed and the proxy object will need to be
-         * re-initialized in this case.
-         */
-        binder.linkToDeath(recipient, 0);
-
-        IGsid gsid = IGsid.Stub.asInterface(binder);
-        return gsid.getClient();
-    }
-
-    /** implements DeathRecipient */
-    @Override
-    public void binderDied() {
-        Slog.w(TAG, "gsiservice died; reconnecting");
-        synchronized (this) {
-            mGsiService = null;
-        }
-    }
-
     private IGsiService getGsiService() throws RemoteException {
         checkPermission();
-
-        if (!"running".equals(SystemProperties.get("init.svc.gsid"))) {
-            SystemProperties.set("ctl.start", "gsid");
+        if (mGsiService != null) {
+            return mGsiService;
         }
-
-        for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) {
-            synchronized (this) {
-                if (mGsiService == null) {
-                    mGsiService = connect(this);
-                }
-                if (mGsiService != null) {
-                    return mGsiService;
-                }
-            }
-
-            try {
-                Slog.d(TAG, "GsiService is not ready, wait for " + sleepMs + "ms");
-                Thread.sleep(sleepMs);
-            } catch (InterruptedException e) {
-                Slog.e(TAG, "Interrupted when waiting for GSID");
-                return null;
-            }
-        }
-
-        throw new RemoteException(NO_SERVICE_ERROR);
+        return IGsiService.Stub.asInterface(waitForService("gsiservice"));
     }
 
     private void checkPermission() {
@@ -133,6 +83,7 @@
     @Override
     public boolean startInstallation(String dsuSlot) throws RemoteException {
         IGsiService service = getGsiService();
+        mGsiService = service;
         // priority from high to low: sysprop -> sdcard -> /data
         String path = SystemProperties.get("os.aot.path");
         if (path.isEmpty()) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index acd4039..d814b9c 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -200,7 +200,7 @@
     // time
     private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
 
-    private static final String FEATURE_ID = "LocationService";
+    private static final String ATTRIBUTION_TAG = "LocationService";
 
     private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
 
@@ -246,7 +246,7 @@
     private int mBatterySaverMode;
 
     private LocationManagerService(Context context) {
-        mContext = context.createFeatureContext(FEATURE_ID);
+        mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mHandler = FgThread.getHandler();
         mLocalService = new LocalService();
 
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index b464422..52a1b5a 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -354,6 +354,10 @@
      */
     public void onPackageFailure(List<VersionedPackage> packages,
             @FailureReasons int failureReason) {
+        if (packages == null) {
+            Slog.w(TAG, "Could not resolve a list of failing packages");
+            return;
+        }
         mLongTaskHandler.post(() -> {
             synchronized (mLock) {
                 if (mAllObservers.isEmpty()) {
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 80036bb..808d322 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -99,6 +99,8 @@
     private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
     private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
 
+    private static final String DEVICE_CONFIG_DISABLE_FLAG = "disable_rescue_party";
+
     private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
             | ApplicationInfo.FLAG_SYSTEM;
 
@@ -114,6 +116,14 @@
             return false;
         }
 
+        // We're disabled if the DeviceConfig disable flag is set to true.
+        // This is in case that an emergency rollback of the feature is needed.
+        if (DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_CONFIGURATION, DEVICE_CONFIG_DISABLE_FLAG, false)) {
+            Slog.v(TAG, "Disabled because of DeviceConfig flag");
+            return true;
+        }
+
         // We're disabled on all engineering devices
         if (Build.IS_ENG) {
             Slog.v(TAG, "Disabled because of eng build");
diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
index 9082dca..db3db0c 100644
--- a/services/core/java/com/android/server/SensorNotificationService.java
+++ b/services/core/java/com/android/server/SensorNotificationService.java
@@ -48,7 +48,7 @@
 
     private static final long MILLIS_2010_1_1 = 1262358000000l;
 
-    private static final String FEATURE_ID = "SensorNotificationService";
+    private static final String ATTRIBUTION_TAG = "SensorNotificationService";
 
     private Context mContext;
     private SensorManager mSensorManager;
@@ -59,7 +59,7 @@
     private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME;
 
     public SensorNotificationService(Context context) {
-        super(context.createFeatureContext(FEATURE_ID));
+        super(context.createAttributionContext(ATTRIBUTION_TAG));
         mContext = getContext();
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b7d050a..2c220d3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -154,7 +154,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.pm.Installer;
 import com.android.server.storage.AppFuseBridge;
 import com.android.server.storage.StorageSessionController;
@@ -233,6 +232,8 @@
     private static final String FUSE_ENABLED = "fuse_enabled";
     private static final boolean DEFAULT_FUSE_ENABLED = true;
 
+    private final Set<Integer> mFuseMountedUser = new ArraySet<>();
+
     public static class Lifecycle extends SystemService {
         private StorageManagerService mStorageManagerService;
 
@@ -1497,6 +1498,9 @@
 
     @GuardedBy("mLock")
     private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
+        if (vol.type == VolumeInfo.TYPE_EMULATED && newState != VolumeInfo.STATE_MOUNTED) {
+            mFuseMountedUser.remove(vol.getMountUserId());
+        }
         // Remember that we saw this volume so we're ready to accept user
         // metadata, or so we can annoy them when a private volume is ejected
         if (!TextUtils.isEmpty(vol.fsUuid)) {
@@ -2075,39 +2079,86 @@
         mount(vol);
     }
 
+    private void remountAppStorageDirs(Map<Integer, String> pidPkgMap, int userId) {
+        for (Entry<Integer, String> entry : pidPkgMap.entrySet()) {
+            final int pid = entry.getKey();
+            final String packageName = entry.getValue();
+            Slog.i(TAG, "Remounting storage for pid: " + pid);
+            final String[] sharedPackages =
+                    mPmInternal.getSharedUserPackagesForPackage(packageName, userId);
+            final int uid = mPmInternal.getPackageUidInternal(packageName, 0, userId);
+            final String[] packages =
+                    sharedPackages.length != 0 ? sharedPackages : new String[]{packageName};
+            try {
+                mVold.remountAppStorageDirs(uid, pid, packages);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+    }
+
     private void mount(VolumeInfo vol) {
         try {
             // TODO(b/135341433): Remove paranoid logging when FUSE is stable
             Slog.i(TAG, "Mounting volume " + vol);
             mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
-                    @Override
-                    public boolean onVolumeChecking(FileDescriptor fd, String path,
-                            String internalPath) {
-                        vol.path = path;
-                        vol.internalPath = internalPath;
-                        ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
-                        try {
-                            mStorageSessionController.onVolumeMount(pfd, vol);
-                            return true;
-                        } catch (ExternalStorageServiceException e) {
-                            Slog.e(TAG, "Failed to mount volume " + vol, e);
+                @Override
+                public boolean onVolumeChecking(FileDescriptor fd, String path,
+                        String internalPath) {
+                    vol.path = path;
+                    vol.internalPath = internalPath;
+                    ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
+                    try {
+                        mStorageSessionController.onVolumeMount(pfd, vol);
+                        return true;
+                    } catch (ExternalStorageServiceException e) {
+                        Slog.e(TAG, "Failed to mount volume " + vol, e);
 
-                            int nextResetSeconds = REMOTE_TIMEOUT_SECONDS * 2;
-                            Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
-                            mHandler.removeMessages(H_RESET);
-                            mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
-                                    TimeUnit.SECONDS.toMillis(nextResetSeconds));
-                            return false;
-                        } finally {
-                            try {
-                                pfd.close();
-                            } catch (Exception e) {
-                                Slog.e(TAG, "Failed to close FUSE device fd", e);
-                            }
+                        int nextResetSeconds = REMOTE_TIMEOUT_SECONDS * 2;
+                        Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
+                        mHandler.removeMessages(H_RESET);
+                        mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
+                                TimeUnit.SECONDS.toMillis(nextResetSeconds));
+                        return false;
+                    } finally {
+                        try {
+                            pfd.close();
+                        } catch (Exception e) {
+                            Slog.e(TAG, "Failed to close FUSE device fd", e);
                         }
                     }
-                });
+                }
+            });
             Slog.i(TAG, "Mounted volume " + vol);
+            if (vol.type == VolumeInfo.TYPE_EMULATED) {
+                final int userId = vol.getMountUserId();
+                mFuseMountedUser.add(userId);
+                // Async remount app storage so it won't block the main thread.
+                new Thread(() -> {
+                    Map<Integer, String> pidPkgMap = null;
+                    // getProcessesWithPendingBindMounts() could fail when a new app process is
+                    // starting and it's not planning to mount storage dirs in zygote, but it's
+                    // rare, so we retry 5 times and hope we can get the result successfully.
+                    for (int i = 0; i < 5; i++) {
+                        try {
+                            pidPkgMap = LocalServices.getService(ActivityManagerInternal.class)
+                                    .getProcessesWithPendingBindMounts(vol.getMountUserId());
+                            break;
+                        } catch (IllegalStateException e) {
+                            Slog.i(TAG, "Some processes are starting, retry");
+                            // Wait 100ms and retry so hope the pending process is started.
+                            SystemClock.sleep(100);
+                        }
+                    }
+                    if (pidPkgMap != null) {
+                        remountAppStorageDirs(pidPkgMap, userId);
+                    } else {
+                        Slog.wtf(TAG, "Not able to getStorageNotOptimizedProcesses() after"
+                                + " 5 retries");
+                    }
+
+                }).start();
+            }
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
@@ -4309,7 +4360,8 @@
             pw.println();
             pw.println("mObbPathToStateMap:");
             pw.increaseIndent();
-            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
+            final Iterator<Entry<String, ObbState>> maps =
+                    mObbPathToStateMap.entrySet().iterator();
             while (maps.hasNext()) {
                 final Entry<String, ObbState> e = maps.next();
                 pw.print(e.getKey());
@@ -4350,45 +4402,41 @@
         }
 
         /**
-         * Check if fuse is running in target user, if it's running then setup its obb directories.
-         * TODO: System server should store a list of active pids that obb is not mounted and use it.
+         * Check if fuse is running in target user, if it's running then setup its storage dirs.
+         * Return true if storage dirs are mounted.
          */
         @Override
-        public void prepareObbDirs(int userId, Set<String> packageList, String processName) {
-            String fuseRunningUsersList = SystemProperties.get("vold.fuse_running_users", "");
-            String[] fuseRunningUsers = fuseRunningUsersList.split(",");
-            boolean fuseReady = false;
-            String targetUserId = String.valueOf(userId);
-            for (String user : fuseRunningUsers) {
-                if (targetUserId.equals(user)) {
-                    fuseReady = true;
-                }
+        public boolean prepareStorageDirs(int userId, Set<String> packageList,
+                String processName) {
+            if (!mFuseMountedUser.contains(userId)) {
+                Slog.w(TAG, "User " + userId + " is not unlocked yet so skip mounting obb");
+                return false;
             }
-            if (fuseReady) {
-                try {
-                    final IVold vold = IVold.Stub.asInterface(
-                            ServiceManager.getServiceOrThrow("vold"));
-                    for (String pkg : packageList) {
-                        final String packageObbDir =
-                                String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg);
-                        final String packageDataDir =
-                                String.format("/storage/emulated/%d/Android/data/%s/",
-                                        userId, pkg);
+            try {
+                final IVold vold = IVold.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow("vold"));
+                for (String pkg : packageList) {
+                    final String packageObbDir =
+                            String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg);
+                    final String packageDataDir =
+                            String.format("/storage/emulated/%d/Android/data/%s/",
+                                    userId, pkg);
 
-                        // Create package obb and data dir if it doesn't exist.
-                        File file = new File(packageObbDir);
-                        if (!file.exists()) {
-                            vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid());
-                        }
-                        file = new File(packageDataDir);
-                        if (!file.exists()) {
-                            vold.setupAppDir(packageDataDir, mPmInternal.getPackage(pkg).getUid());
-                        }
+                    // Create package obb and data dir if it doesn't exist.
+                    File file = new File(packageObbDir);
+                    if (!file.exists()) {
+                        vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid());
                     }
-                } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
-                    Slog.e(TAG, "Unable to create obb and data directories for " + processName, e);
+                    file = new File(packageDataDir);
+                    if (!file.exists()) {
+                        vold.setupAppDir(packageDataDir, mPmInternal.getPackage(pkg).getUid());
+                    }
                 }
+            } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
+                Slog.e(TAG, "Unable to create obb and data directories for " + processName,e);
+                return false;
             }
+            return true;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index eace86b..12a1a95 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1318,9 +1318,9 @@
             if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
                 try {
                     int result = ActivityTaskManager.getService().startActivityWithConfig(
-                            null, getContext().getBasePackageName(), getContext().getFeatureId(),
-                            homeIntent, null, null, null, 0, 0, mConfiguration, null,
-                            UserHandle.USER_CURRENT);
+                            null, getContext().getBasePackageName(),
+                            getContext().getAttributionTag(), homeIntent, null, null, null, 0, 0,
+                            mConfiguration, null, UserHandle.USER_CURRENT);
                     if (ActivityManager.isStartResultSuccessful(result)) {
                         dockAppStarted = true;
                     } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cfc8b45..0ebb5bb 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -137,6 +137,10 @@
 
     private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
 
+    //TODO: remove this when development is done.
+    private static final int DEBUG_FGS_ALLOW_WHILE_IN_USE = 0;
+    private static final int DEBUG_FGS_ENFORCE_TYPE = 1;
+
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
 
@@ -1701,7 +1705,7 @@
                     if (acceptances > 0 ||  rejections > 0) {
                         FrameworkStatsLog.write(
                                 FrameworkStatsLog.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED,
-                                mProcessRecord.uid, opToEnum(op),
+                                mProcessRecord.uid, AppOpsManager.opToLoggingId(op),
                                 modeToEnum(mAppOpModes.get(op)),
                                 acceptances, rejections
                         );
@@ -1725,22 +1729,6 @@
         }
     }
 
-    /** Maps AppOp op value to atoms.proto enum. */
-    private static int opToEnum(int op) {
-        switch (op) {
-            case AppOpsManager.OP_COARSE_LOCATION: return FrameworkStatsLog
-                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_COARSE_LOCATION;
-            case AppOpsManager.OP_FINE_LOCATION: return FrameworkStatsLog
-                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_FINE_LOCATION;
-            case AppOpsManager.OP_CAMERA: return FrameworkStatsLog
-                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_CAMERA;
-            case AppOpsManager.OP_RECORD_AUDIO: return FrameworkStatsLog
-                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_RECORD_AUDIO;
-            default: return FrameworkStatsLog
-                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_NONE;
-        }
-    }
-
     private void cancelForegroundNotificationLocked(ServiceRecord r) {
         if (r.foregroundId != 0) {
             // First check to see if this app has any other active foreground services
@@ -4931,10 +4919,20 @@
                 if (!r.isForeground) {
                     continue;
                 }
-                if (!r.mAllowWhileInUsePermissionInFgs
-                        && r.mInfoDenyWhileInUsePermissionInFgs != null) {
-                    final String msg = r.mInfoDenyWhileInUsePermissionInFgs
-                            + " affected while-in-use permission:"
+                if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE) {
+                    if (!r.mAllowWhileInUsePermissionInFgs
+                            && r.mInfoDenyWhileInUsePermissionInFgs != null) {
+                        final String msg = r.mInfoDenyWhileInUsePermissionInFgs
+                                + " affected while-in-use permission:"
+                                + AppOpsManager.opToPublicName(op);
+                        Slog.wtf(TAG, msg);
+                    }
+                } else if (mode == DEBUG_FGS_ENFORCE_TYPE) {
+                    final String msg =
+                            "FGS Missing foregroundServiceType in manifest file [callingPackage: "
+                            + r.mRecentCallingPackage
+                            + "; intent:" + r.intent.getIntent()
+                            + "] affected while-in-use permission:"
                             + AppOpsManager.opToPublicName(op);
                     Slog.wtf(TAG, msg);
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f64272b..4485af1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17538,8 +17538,11 @@
 
     final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
         if (proc.thread != null && proc.baseProcessTracker != null) {
-            proc.baseProcessTracker.setState(
-                    proc.getReportedProcState(), memFactor, now, proc.pkgList.mPkgList);
+            final int procState = proc.getReportedProcState();
+            if (procState != PROCESS_STATE_NONEXISTENT) {
+                proc.baseProcessTracker.setState(
+                        procState, memFactor, now, proc.pkgList.mPkgList);
+            }
         }
     }
 
@@ -18714,6 +18717,11 @@
         }
 
         @Override
+        public Map<Integer, String> getProcessesWithPendingBindMounts(int userId) {
+            return mProcessList.getProcessesWithPendingBindMounts(userId);
+        }
+
+        @Override
         public boolean isSystemReady() {
             // no need to synchronize(this) just to read & return the value
             return mSystemReady;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index b584ea5..2b1534b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -75,7 +75,6 @@
 import android.app.ApplicationExitInfo;
 import android.app.usage.UsageEvents;
 import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
 import android.compat.annotation.EnabledAfter;
 import android.content.Context;
 import android.content.pm.ServiceInfo;
@@ -149,12 +148,13 @@
      * capabilities.
      */
     @ChangeId
-    //TODO: change to @EnabledAfter when enforcing the feature.
-    @Disabled
+    @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
     static final long CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID = 136219221L;
 
     //TODO: remove this when development is done.
     private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
+    private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30;
+    private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29;
 
     /**
      * For some direct access we need to power manager.
@@ -1513,10 +1513,12 @@
                     if (enabled) {
                         capabilityFromFGS |=
                                 (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
-                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
+                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
+                                        : TEMP_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
                         capabilityFromFGS |=
                                 (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
-                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
+                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
+                                        : TEMP_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
                     } else {
                         capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
                                 | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 6b16513..57bd42b 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -61,6 +61,7 @@
 import android.app.IApplicationThread;
 import android.app.IUidObserver;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
 import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -70,6 +71,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProcessInfo;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.net.LocalSocket;
@@ -97,6 +99,7 @@
 import android.system.Os;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.LongSparseArray;
 import android.util.Pair;
@@ -134,8 +137,11 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Activity manager code dealing with processes.
@@ -152,7 +158,8 @@
             "persist.sys.vold_app_data_isolation_enabled";
 
     // A device config to control the minimum target SDK to enable app data isolation
-    static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK = "android_app_data_isolation_min_sdk";
+    static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK =
+            "android_app_data_isolation_min_sdk";
 
     // The minimum time we allow between crashes, for us to consider this
     // application to be bad and stop and its services and reject broadcasts.
@@ -345,6 +352,14 @@
     private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
 
     /**
+     * Enable sampled memory bug detection in the app.
+     * @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
+     */
+    @ChangeId
+    @Disabled
+    private static final long GWP_ASAN = 135634846; // This is a bug id.
+
+    /**
      * Apps have no access to the private data directories of any other app, even if the other
      * app has made them world-readable.
      */
@@ -789,6 +804,31 @@
         }
     }
 
+    /**
+     * Get a map of pid and package name that process of that pid Android/data and Android/obb
+     * directory is not mounted to lowerfs to speed up access.
+     */
+    Map<Integer, String> getProcessesWithPendingBindMounts(int userId) {
+        final Map<Integer, String> pidPackageMap = new HashMap<>();
+        synchronized (mService) {
+            for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+                final ProcessRecord record = mLruProcesses.get(i);
+                if (record.userId != userId || !record.bindMountPending) {
+                    continue;
+                }
+                final int pid = record.pid;
+                // It can happen when app process is starting, but zygote work is not done yet so
+                // system does not this pid record yet.
+                if (pid == 0) {
+                    throw new IllegalStateException("Pending process is not started yet,"
+                            + "retry later");
+                }
+                pidPackageMap.put(pid, record.info.packageName);
+            }
+            return pidPackageMap;
+        }
+    }
+
     private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
         // Scale buckets from avail memory: at 300MB we use the lowest values to
         // 700MB or more for the top values.
@@ -1634,6 +1674,28 @@
         return gidArray;
     }
 
+    private int decideGwpAsanLevel(ProcessRecord app) {
+        // Look at the process attribute first.
+        if (app.processInfo != null && app.processInfo.enableGwpAsan != null) {
+            return app.processInfo.enableGwpAsan ? Zygote.GWP_ASAN_LEVEL_ALWAYS
+                                                 : Zygote.GWP_ASAN_LEVEL_NEVER;
+        }
+        // Then at the applicaton attribute.
+        if (app.info.isGwpAsanEnabled() != null) {
+            return app.info.isGwpAsanEnabled() ? Zygote.GWP_ASAN_LEVEL_ALWAYS
+                                               : Zygote.GWP_ASAN_LEVEL_NEVER;
+        }
+        // If the app does not specify enableGwpAsan, the default behavior is lottery among the
+        // system apps, and disabled for user apps, unless overwritten by the compat feature.
+        if (mPlatformCompat.isChangeEnabled(GWP_ASAN, app.info)) {
+            return Zygote.GWP_ASAN_LEVEL_ALWAYS;
+        }
+        if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+            return Zygote.GWP_ASAN_LEVEL_LOTTERY;
+        }
+        return Zygote.GWP_ASAN_LEVEL_NEVER;
+    }
+
     /**
      * @return {@code true} if process start is successful, false otherwise.
      */
@@ -1648,6 +1710,7 @@
         if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
             checkSlow(startTime, "startProcess: removing from pids map");
             mService.removePidLocked(app);
+            app.bindMountPending = false;
             mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             checkSlow(startTime, "startProcess: done removing from pids map");
             app.setPid(0);
@@ -1803,6 +1866,8 @@
                 runtimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
             }
 
+            runtimeFlags |= decideGwpAsanLevel(app);
+
             String invokeWith = null;
             if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                 // Debuggable apps may include a wrapper script with their library directory.
@@ -2128,8 +2193,10 @@
             }
 
             final Map<String, Pair<String, Long>> pkgDataInfoMap;
+            boolean bindMountAppStorageDirs = false;
 
             if (shouldIsolateAppData(app)) {
+                bindMountAppStorageDirs = mVoldAppDataIsolationEnabled;
                 // Get all packages belongs to the same shared uid. sharedPackages is empty array
                 // if it doesn't have shared uid.
                 final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
@@ -2138,11 +2205,17 @@
                 pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
                         ? new String[]{app.info.packageName} : sharedPackages, uid);
 
+                int userId = UserHandle.getUserId(uid);
                 if (mVoldAppDataIsolationEnabled) {
                     StorageManagerInternal storageManagerInternal = LocalServices.getService(
-                                StorageManagerInternal.class);
-                    storageManagerInternal.prepareObbDirs(UserHandle.getUserId(uid),
-                            pkgDataInfoMap.keySet(), app.processName);
+                            StorageManagerInternal.class);
+                    if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
+                            app.processName)) {
+                        // Cannot prepare Android/app and Android/obb directory,
+                        // so we won't mount it in zygote.
+                        app.bindMountPending = true;
+                        bindMountAppStorageDirs = false;
+                    }
                 }
             } else {
                 pkgDataInfoMap = null;
@@ -2163,7 +2236,7 @@
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, app.info.packageName,
                         /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
-                        app.mDisabledCompatChanges, pkgDataInfoMap,
+                        app.mDisabledCompatChanges, pkgDataInfoMap, bindMountAppStorageDirs,
                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});
             } else {
                 startResult = Process.start(entryPoint,
@@ -2171,6 +2244,7 @@
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
                         isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
+                        bindMountAppStorageDirs,
                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});
             }
             checkSlow(startTime, "startProcess: returned from zygote!");
@@ -2629,6 +2703,7 @@
             int pid = app.pid;
             if (pid > 0) {
                 mService.removePidLocked(app);
+                app.bindMountPending = false;
                 mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
                 mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
                 if (app.isolated) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c029811..e7f66bb 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -251,6 +251,7 @@
     int adjSourceProcState;     // Debugging: proc state of adjSource's process.
     Object adjTarget;           // Debugging: target component impacting oom_adj.
     Runnable crashHandler;      // Optional local handler to be invoked in the process crash.
+    boolean bindMountPending;   // True if Android/obb and Android/data need to be bind mount .
 
     // Cache of last retrieve memory info and uptime, to throttle how frequently
     // apps can requyest it.
@@ -384,6 +385,9 @@
                     pw.println(processInfo.deniedPermissions.valueAt(i));
                 }
             }
+            if (processInfo.enableGwpAsan != null) {
+                pw.print(prefix); pw.println("  enableGwpAsan=" + processInfo.enableGwpAsan);
+            }
         }
         pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi);
                 pw.print(" instructionSet="); pw.println(instructionSet);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 0a8e70c..bac7565 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -80,6 +80,7 @@
     @VisibleForTesting
     static final String[] sDeviceConfigScopes = new String[] {
         DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+        DeviceConfig.NAMESPACE_CONFIGURATION,
         DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
         DeviceConfig.NAMESPACE_MEDIA_NATIVE,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 87e1dbc..2e2241f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -20,7 +20,7 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
-import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
 import static android.app.AppOpsManager.FILTER_BY_UID;
@@ -41,6 +41,7 @@
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OpEventProxyInfo;
 import static android.app.AppOpsManager.RestrictionBypass;
+import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
@@ -77,10 +78,10 @@
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.AppOpsManager.AttributedOpEntry;
 import android.app.AppOpsManager.HistoricalOps;
 import android.app.AppOpsManager.Mode;
 import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.OpFeatureEntry;
 import android.app.AppOpsManager.OpFlags;
 import android.app.AppOpsManagerInternal;
 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
@@ -97,7 +98,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
 import android.database.ContentObserver;
 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
 import android.net.Uri;
@@ -244,9 +245,15 @@
 
     private static final int MAX_UNFORWARED_OPS = 10;
     private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
+    private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
 
     //TODO: remove this when development is done.
     private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
+    private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30;
+    private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29;
+    private static final int DEBUG_FGS_ALLOW_WHILE_IN_USE = 0;
+    private static final int DEBUG_FGS_ENFORCE_TYPE = 1;
+
 
     final Context mContext;
     final AtomicFile mFile;
@@ -371,14 +378,14 @@
         }
 
         OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
-                @Nullable String featureId) {
+                @Nullable String attributionTag) {
             OpEventProxyInfo recycled = acquire();
             if (recycled != null) {
-                recycled.reinit(uid, packageName, featureId);
+                recycled.reinit(uid, packageName, attributionTag);
                 return recycled;
             }
 
-            return new OpEventProxyInfo(uid, packageName, featureId);
+            return new OpEventProxyInfo(uid, packageName, attributionTag);
         }
     }
 
@@ -549,7 +556,7 @@
                                 // The FGS has the location capability, but due to FGS BG start
                                 // restriction it lost the capability, use temp location capability
                                 // to mark this case.
-                                maybeShowWhileInUseDebugToast(op, mode);
+                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                                 return MODE_IGNORED;
                             } else {
                                 return MODE_IGNORED;
@@ -557,15 +564,25 @@
                         case OP_CAMERA:
                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
                                 return MODE_ALLOWED;
+                            } else if ((capability & TEMP_PROCESS_CAPABILITY_FOREGROUND_CAMERA)
+                                    != 0) {
+                                // CHANGE TO MODE_IGNORED when enforce this feature.
+                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
+                                return MODE_ALLOWED;
                             } else {
-                                maybeShowWhileInUseDebugToast(op, mode);
+                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                                 return MODE_IGNORED;
                             }
                         case OP_RECORD_AUDIO:
                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
                                 return MODE_ALLOWED;
+                            } else if  ((capability & TEMP_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE)
+                                    != 0) {
+                                // CHANGE TO MODE_IGNORED when enforce this feature.
+                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
+                                return MODE_ALLOWED;
                             } else {
-                                maybeShowWhileInUseDebugToast(op, mode);
+                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                                 return MODE_IGNORED;
                             }
                         default:
@@ -580,15 +597,24 @@
                     case OP_CAMERA:
                         if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
                             return MODE_ALLOWED;
+                        } else if ((capability & TEMP_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
+                            // CHANGE TO MODE_IGNORED when enforce this feature.
+                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
+                            return MODE_ALLOWED;
                         } else {
-                            maybeShowWhileInUseDebugToast(op, mode);
+                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                             return MODE_IGNORED;
                         }
                     case OP_RECORD_AUDIO:
                         if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
                             return MODE_ALLOWED;
+                        } else if ((capability & TEMP_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE)
+                                != 0) {
+                            // CHANGE TO MODE_IGNORED when enforce this feature.
+                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
+                            return MODE_ALLOWED;
                         } else {
-                            maybeShowWhileInUseDebugToast(op, mode);
+                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                             return MODE_IGNORED;
                         }
                     default:
@@ -671,8 +697,8 @@
          */
         @Nullable RestrictionBypass bypass;
 
-        /** Lazily populated cache of featureIds of this package */
-        final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
+        /** Lazily populated cache of attributionTags of this package */
+        final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
 
         Ops(String _packageName, UidState _uidState) {
             packageName = _packageName;
@@ -776,8 +802,8 @@
         }
     }
 
-    private final class FeatureOp {
-        public final @Nullable String featureId;
+    private final class AttributedOp {
+        public final @Nullable String tag;
         public final @NonNull Op parent;
 
         /**
@@ -804,8 +830,8 @@
         @GuardedBy("AppOpsService.this")
         private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
 
-        FeatureOp(@Nullable String featureId, @NonNull Op parent) {
-            this.featureId = featureId;
+        AttributedOp(@Nullable String tag, @NonNull Op parent) {
+            this.tag = tag;
             this.parent = parent;
         }
 
@@ -814,18 +840,18 @@
          *
          * @param proxyUid The uid of the proxy
          * @param proxyPackageName The package name of the proxy
-         * @param proxyFeatureId the featureId in the proxies package
+         * @param proxyAttributionTag the attributionTag in the proxies package
          * @param uidState UID state of the app noteOp/startOp was called for
          * @param flags OpFlags of the call
          */
         public void accessed(int proxyUid, @Nullable String proxyPackageName,
-                @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
+                @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
                 @OpFlags int flags) {
             accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
-                    proxyFeatureId, uidState, flags);
+                    proxyAttributionTag, uidState, flags);
 
             mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
-                    featureId, uidState, flags);
+                    tag, uidState, flags);
         }
 
         /**
@@ -835,12 +861,12 @@
          * @param duration The duration of the event
          * @param proxyUid The uid of the proxy
          * @param proxyPackageName The package name of the proxy
-         * @param proxyFeatureId the featureId in the proxies package
+         * @param proxyAttributionTag the attributionTag in the proxies package
          * @param uidState UID state of the app noteOp/startOp was called for
          * @param flags OpFlags of the call
          */
         public void accessed(long noteTime, long duration, int proxyUid,
-                @Nullable String proxyPackageName, @Nullable String proxyFeatureId,
+                @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
                 @AppOpsManager.UidState int uidState, @OpFlags int flags) {
             long key = makeKey(uidState, flags);
 
@@ -851,7 +877,7 @@
             OpEventProxyInfo proxyInfo = null;
             if (proxyUid != Process.INVALID_UID) {
                 proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
-                        proxyFeatureId);
+                        proxyAttributionTag);
             }
 
             NoteOpEvent existingEvent = mAccessEvents.get(key);
@@ -872,7 +898,7 @@
             rejected(System.currentTimeMillis(), uidState, flags);
 
             mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, parent.packageName,
-                    featureId, uidState, flags);
+                    tag, uidState, flags);
         }
 
         /**
@@ -938,7 +964,7 @@
 
             // startOp events don't support proxy, hence use flags==SELF
             mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
-                    featureId, uidState, OP_FLAG_SELF);
+                    tag, uidState, OP_FLAG_SELF);
         }
 
         /**
@@ -978,7 +1004,7 @@
                 mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
 
                 mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
-                        parent.packageName, featureId, event.getUidState(),
+                        parent.packageName, tag, event.getUidState(),
                         AppOpsManager.OP_FLAG_SELF, finishedEvent.getDuration());
 
                 mInProgressStartOpEventPool.release(event);
@@ -986,7 +1012,7 @@
                 if (mInProgressEvents.isEmpty()) {
                     mInProgressEvents = null;
 
-                    // TODO moltmann: Also callback for single feature activity changes
+                    // TODO moltmann: Also callback for single attribution tag activity changes
                     if (triggerCallbackIfNeeded && !parent.isRunning()) {
                         scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                                 parent.packageName, false);
@@ -1077,14 +1103,14 @@
         }
 
         /**
-         * Add all data from the {@code featureToAdd} to this op.
+         * Add all data from the {@code opToAdd} to this op.
          *
          * <p>If there is an event for the same key in both the later event is retained.
          * <p>{@code opToAdd} should not be used after this method is called.
          *
          * @param opToAdd The op to add
          */
-        public void add(@NonNull FeatureOp opToAdd) {
+        public void add(@NonNull AttributedOp opToAdd) {
             if (opToAdd.mInProgressEvents != null) {
                 Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops");
 
@@ -1128,7 +1154,7 @@
             return clone;
         }
 
-        @NonNull OpFeatureEntry createFeatureEntryLocked() {
+        @NonNull AttributedOpEntry createAttributedOpEntryLocked() {
             LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
 
             // Add in progress events as access events
@@ -1152,7 +1178,7 @@
 
             LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
 
-            return new OpFeatureEntry(parent.op, isRunning(), accessEvents, rejectEvents);
+            return new AttributedOpEntry(parent.op, isRunning(), accessEvents, rejectEvents);
         }
     }
 
@@ -1164,8 +1190,8 @@
 
         private @Mode int mode;
 
-        /** featureId -> FeatureOp */
-        final ArrayMap<String, FeatureOp> mFeatures = new ArrayMap<>(1);
+        /** attributionTag -> AttributedOp */
+        final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1);
 
         Op(UidState uidState, String packageName, int op, int uid) {
             this.op = op;
@@ -1183,58 +1209,59 @@
             return uidState.evalMode(op, mode);
         }
 
-        void removeFeaturesWithNoTime() {
-            for (int i = mFeatures.size() - 1; i >= 0; i--) {
-                if (!mFeatures.valueAt(i).hasAnyTime()) {
-                    mFeatures.removeAt(i);
+        void removeAttributionsWithNoTime() {
+            for (int i = mAttributions.size() - 1; i >= 0; i--) {
+                if (!mAttributions.valueAt(i).hasAnyTime()) {
+                    mAttributions.removeAt(i);
                 }
             }
         }
 
-        private @NonNull FeatureOp getOrCreateFeature(@NonNull Op parent,
-                @Nullable String featureId) {
-            FeatureOp featureOp;
+        private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent,
+                @Nullable String attributionTag) {
+            AttributedOp attributedOp;
 
-            featureOp = mFeatures.get(featureId);
-            if (featureOp == null) {
-                featureOp = new FeatureOp(featureId, parent);
-                mFeatures.put(featureId, featureOp);
+            attributedOp = mAttributions.get(attributionTag);
+            if (attributedOp == null) {
+                attributedOp = new AttributedOp(attributionTag, parent);
+                mAttributions.put(attributionTag, attributedOp);
             }
 
-            return featureOp;
+            return attributedOp;
         }
 
         @NonNull OpEntry createEntryLocked() {
-            final int numFeatures = mFeatures.size();
+            final int numAttributions = mAttributions.size();
 
-            final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(numFeatures);
-            for (int i = 0; i < numFeatures; i++) {
-                featureEntries.put(mFeatures.keyAt(i),
-                        mFeatures.valueAt(i).createFeatureEntryLocked());
+            final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
+                    new ArrayMap<>(numAttributions);
+            for (int i = 0; i < numAttributions; i++) {
+                attributionEntries.put(mAttributions.keyAt(i),
+                        mAttributions.valueAt(i).createAttributedOpEntryLocked());
             }
 
-            return new OpEntry(op, mode, featureEntries);
+            return new OpEntry(op, mode, attributionEntries);
         }
 
-        @NonNull OpEntry createSingleFeatureEntryLocked(@Nullable String featureId) {
-            final int numFeatures = mFeatures.size();
+        @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
+            final int numAttributions = mAttributions.size();
 
-            final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(1);
-            for (int i = 0; i < numFeatures; i++) {
-                if (Objects.equals(mFeatures.keyAt(i), featureId)) {
-                    featureEntries.put(mFeatures.keyAt(i),
-                            mFeatures.valueAt(i).createFeatureEntryLocked());
+            final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
+            for (int i = 0; i < numAttributions; i++) {
+                if (Objects.equals(mAttributions.keyAt(i), attributionTag)) {
+                    attributionEntries.put(mAttributions.keyAt(i),
+                            mAttributions.valueAt(i).createAttributedOpEntryLocked());
                     break;
                 }
             }
 
-            return new OpEntry(op, mode, featureEntries);
+            return new OpEntry(op, mode, attributionEntries);
         }
 
         boolean isRunning() {
-            final int numFeatures = mFeatures.size();
-            for (int i = 0; i < numFeatures; i++) {
-                if (mFeatures.valueAt(i).isRunning()) {
+            final int numAttributions = mAttributions.size();
+            for (int i = 0; i < numAttributions; i++) {
+                if (mAttributions.valueAt(i).isRunning()) {
                     return true;
                 }
             }
@@ -1407,10 +1434,11 @@
     }
 
     /**
-     * Call {@link FeatureOp#onClientDeath featureOp.onClientDeath(clientId)}.
+     * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}.
      */
-    private static void onClientDeath(@NonNull FeatureOp featureOp, @NonNull IBinder clientId) {
-        featureOp.onClientDeath(clientId);
+    private static void onClientDeath(@NonNull AttributedOp attributedOp,
+            @NonNull IBinder clientId) {
+        attributedOp.onClientDeath(clientId);
     }
 
 
@@ -1492,20 +1520,21 @@
                     return;
                 }
 
-                ArrayMap<String, String> dstFeatureIds = new ArrayMap<>();
-                ArraySet<String> featureIds = new ArraySet<>();
-                featureIds.add(null);
-                if (pkg.getFeatures() != null) {
-                    int numFeatures = pkg.getFeatures().size();
-                    for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                        ParsedFeature feature = pkg.getFeatures().get(featureNum);
-                        featureIds.add(feature.id);
+                ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
+                ArraySet<String> attributionTags = new ArraySet<>();
+                attributionTags.add(null);
+                if (pkg.getAttributions() != null) {
+                    int numAttributions = pkg.getAttributions().size();
+                    for (int attributionNum = 0; attributionNum < numAttributions;
+                            attributionNum++) {
+                        ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
+                        attributionTags.add(attribution.tag);
 
-                        int numInheritFrom = feature.inheritFrom.size();
+                        int numInheritFrom = attribution.inheritFrom.size();
                         for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
                                 inheritFromNum++) {
-                            dstFeatureIds.put(feature.inheritFrom.get(inheritFromNum),
-                                    feature.id);
+                            dstAttributionTags.put(attribution.inheritFrom.get(inheritFromNum),
+                                    attribution.tag);
                         }
                     }
                 }
@@ -1523,27 +1552,30 @@
 
                     // Reset cached package properties to re-initialize when needed
                     ops.bypass = null;
-                    ops.knownFeatureIds.clear();
+                    ops.knownAttributionTags.clear();
 
-                    // Merge data collected for removed features into their successor features
+                    // Merge data collected for removed attributions into their successor
+                    // attributions
                     int numOps = ops.size();
                     for (int opNum = 0; opNum < numOps; opNum++) {
                         Op op = ops.valueAt(opNum);
 
-                        int numFeatures = op.mFeatures.size();
-                        for (int featureNum = numFeatures - 1; featureNum >= 0; featureNum--) {
-                            String featureId = op.mFeatures.keyAt(featureNum);
+                        int numAttributions = op.mAttributions.size();
+                        for (int attributionNum = numAttributions - 1; attributionNum >= 0;
+                                attributionNum--) {
+                            String attributionTag = op.mAttributions.keyAt(attributionNum);
 
-                            if (featureIds.contains(featureId)) {
-                                // feature still exist after upgrade
+                            if (attributionTags.contains(attributionTag)) {
+                                // attribution still exist after upgrade
                                 continue;
                             }
 
-                            String newFeatureId = dstFeatureIds.get(featureId);
+                            String newAttributionTag = dstAttributionTags.get(attributionTag);
 
-                            FeatureOp newFeatureOp = op.getOrCreateFeature(op, newFeatureId);
-                            newFeatureOp.add(op.mFeatures.valueAt(featureNum));
-                            op.mFeatures.removeAt(featureNum);
+                            AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
+                                    newAttributionTag);
+                            newAttributedOp.add(op.mAttributions.valueAt(attributionNum));
+                            op.mAttributions.removeAt(attributionNum);
 
                             scheduleFastWriteLocked();
                         }
@@ -1651,17 +1683,14 @@
             }
         }, packageAddedFilter);
 
-        List<String> packageNames = getPackageNamesForSampling();
-        synchronized (this) {
-            resamplePackageAndAppOpLocked(packageNames);
-        }
-
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+        mHandler.postDelayed(new Runnable() {
             @Override
             public void run() {
+                List<String> packageNames = getPackageNamesForSampling();
+                resamplePackageAndAppOpLocked(packageNames);
                 initializeRarelyUsedPackagesList(new ArraySet<>(packageNames));
             }
-        });
+        }, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS);
 
         PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
@@ -1743,12 +1772,13 @@
                 for (int opNum = 0; opNum < numOps; opNum++) {
                     final Op op = ops.valueAt(opNum);
 
-                    final int numFeatures = op.mFeatures.size();
-                    for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                        FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
+                    final int numAttributions = op.mAttributions.size();
+                    for (int attributionNum = 0; attributionNum < numAttributions;
+                            attributionNum++) {
+                        AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum);
 
-                        while (featureOp.mInProgressEvents != null) {
-                            featureOp.finished(featureOp.mInProgressEvents.keyAt(0));
+                        while (attributedOp.mInProgressEvents != null) {
+                            attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0));
                         }
                     }
                 }
@@ -1828,11 +1858,13 @@
                         for (int opNum = 0; opNum < numOps; opNum++) {
                             Op op = ops.valueAt(opNum);
 
-                            int numFeatures = op.mFeatures.size();
-                            for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
-                                FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
+                            int numAttributions = op.mAttributions.size();
+                            for (int attributionNum = 0; attributionNum < numAttributions;
+                                    attributionNum++) {
+                                AttributedOp attributedOp = op.mAttributions.valueAt(
+                                        attributionNum);
 
-                                featureOp.onUidStateChanged(newState);
+                                attributedOp.onUidStateChanged(newState);
                             }
                         }
                     }
@@ -1978,9 +2010,9 @@
     /**
      * Verify that historical appop request arguments are valid.
      */
-    private void ensureHistoricalOpRequestIsValid(int uid, String packageName, String featureId,
-            List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
-            int flags) {
+    private void ensureHistoricalOpRequestIsValid(int uid, String packageName,
+            String attributionTag, List<String> opNames, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags) {
         if ((filter & FILTER_BY_UID) != 0) {
             Preconditions.checkArgument(uid != Process.INVALID_UID);
         } else {
@@ -1993,8 +2025,8 @@
             Preconditions.checkArgument(packageName == null);
         }
 
-        if ((filter & FILTER_BY_FEATURE_ID) == 0) {
-            Preconditions.checkArgument(featureId == null);
+        if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) {
+            Preconditions.checkArgument(attributionTag == null);
         }
 
         if ((filter & FILTER_BY_OP_NAMES) != 0) {
@@ -2004,17 +2036,18 @@
         }
 
         Preconditions.checkFlagsArgument(filter,
-                FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_FEATURE_ID | FILTER_BY_OP_NAMES);
+                FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG
+                        | FILTER_BY_OP_NAMES);
         Preconditions.checkArgumentNonnegative(beginTimeMillis);
         Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
         Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
     }
 
     @Override
-    public void getHistoricalOps(int uid, String packageName, String featureId,
+    public void getHistoricalOps(int uid, String packageName, String attributionTag,
             List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
             int flags, RemoteCallback callback) {
-        ensureHistoricalOpRequestIsValid(uid, packageName, featureId, opNames, filter,
+        ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
                 beginTimeMillis, endTimeMillis, flags);
         Objects.requireNonNull(callback, "callback cannot be null");
 
@@ -2035,15 +2068,15 @@
 
         // Must not hold the appops lock
         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
-                mHistoricalRegistry, uid, packageName, featureId, opNamesArray, filter,
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, filter,
                 beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
     }
 
     @Override
-    public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String featureId,
+    public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
             List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
             int flags, RemoteCallback callback) {
-        ensureHistoricalOpRequestIsValid(uid, packageName, featureId, opNames, filter,
+        ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
                 beginTimeMillis, endTimeMillis, flags);
         Objects.requireNonNull(callback, "callback cannot be null");
 
@@ -2055,7 +2088,7 @@
 
         // Must not hold the appops lock
         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
-                mHistoricalRegistry, uid, packageName, featureId, opNamesArray,
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray,
                 filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
     }
 
@@ -2089,9 +2122,9 @@
     }
 
     private void pruneOpLocked(Op op, int uid, String packageName) {
-        op.removeFeaturesWithNoTime();
+        op.removeAttributionsWithNoTime();
 
-        if (op.mFeatures.size() == 0) {
+        if (op.mAttributions.isEmpty()) {
             Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */);
             if (ops != null) {
                 ops.remove(op.op);
@@ -2610,8 +2643,8 @@
                             callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
                                     mPackageModeWatchers.get(packageName));
 
-                            curOp.removeFeaturesWithNoTime();
-                            if (curOp.mFeatures.size() == 0) {
+                            curOp.removeAttributionsWithNoTime();
+                            if (curOp.mAttributions.isEmpty()) {
                                 pkgOps.removeAt(j);
                             }
                         }
@@ -2895,8 +2928,8 @@
 
     @Override
     public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
-            String proxiedFeatureId, int proxyUid, String proxyPackageName,
-            String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message) {
+            String proxiedAttributionTag, int proxyUid, String proxyPackageName,
+            String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message) {
         verifyIncomingUid(proxyUid);
         verifyIncomingOp(code);
 
@@ -2912,7 +2945,7 @@
         final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
         final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
-                proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags,
+                proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags,
                 !isProxyTrusted, "proxy " + message);
         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
             return proxyMode;
@@ -2925,27 +2958,27 @@
         final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
         return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
-                proxiedFeatureId, proxyUid, resolveProxyPackageName, proxyFeatureId,
+                proxiedAttributionTag, proxyUid, resolveProxyPackageName, proxyAttributionTag,
                 proxiedFlags, shouldCollectAsyncNotedOp, message);
     }
 
     @Override
-    public int noteOperation(int code, int uid, String packageName, String featureId,
+    public int noteOperation(int code, int uid, String packageName, String attributionTag,
             boolean shouldCollectAsyncNotedOp, String message) {
         final CheckOpsDelegate delegate;
         synchronized (this) {
             delegate = mCheckOpsDelegate;
         }
         if (delegate == null) {
-            return noteOperationImpl(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
-                    message);
+            return noteOperationImpl(code, uid, packageName, attributionTag,
+                    shouldCollectAsyncNotedOp, message);
         }
-        return delegate.noteOperation(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
-                message, AppOpsService.this::noteOperationImpl);
+        return delegate.noteOperation(code, uid, packageName, attributionTag,
+                shouldCollectAsyncNotedOp, message, AppOpsService.this::noteOperationImpl);
     }
 
     private int noteOperationImpl(int code, int uid, @Nullable String packageName,
-            @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+            @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
             @Nullable String message) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
@@ -2953,25 +2986,26 @@
         if (resolvedPackageName == null) {
             return AppOpsManager.MODE_IGNORED;
         }
-        return noteOperationUnchecked(code, uid, resolvedPackageName, featureId,
+        return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
                 Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
                 shouldCollectAsyncNotedOp, message);
     }
 
     private int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
-            @Nullable String featureId, int proxyUid, String proxyPackageName,
-            @Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
-            @Nullable String message) {
+            @Nullable String attributionTag, int proxyUid, String proxyPackageName,
+            @Nullable String proxyAttributionTag, @OpFlags int flags,
+            boolean shouldCollectAsyncNotedOp, @Nullable String message) {
         RestrictionBypass bypass;
         try {
-            bypass = verifyAndGetBypass(uid, packageName, featureId);
+            bypass = verifyAndGetBypass(uid, packageName, attributionTag);
         } catch (SecurityException e) {
             Slog.e(TAG, "noteOperation", e);
             return AppOpsManager.MODE_ERRORED;
         }
 
         synchronized (this) {
-            final Ops ops = getOpsLocked(uid, packageName, featureId, bypass, true /* edit */);
+            final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass,
+                    true /* edit */);
             if (ops == null) {
                 scheduleOpNotedIfNeededLocked(code, uid, packageName,
                         AppOpsManager.MODE_IGNORED);
@@ -2980,17 +3014,17 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             final Op op = getOpLocked(ops, code, uid, true);
-            final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
+            final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
             if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
                 scheduleOpNotedIfNeededLocked(code, uid, packageName,
                         AppOpsManager.MODE_IGNORED);
                 return AppOpsManager.MODE_IGNORED;
             }
             final UidState uidState = ops.uidState;
-            if (featureOp.isRunning()) {
+            if (attributedOp.isRunning()) {
                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
                         + code + " startTime of in progress event="
-                        + featureOp.mInProgressEvents.valueAt(0).getStartTime());
+                        + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
             }
 
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -3002,7 +3036,7 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName);
-                    featureOp.rejected(uidState.state, flags);
+                    attributedOp.rejected(uidState.state, flags);
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
                     return uidMode;
                 }
@@ -3014,26 +3048,31 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName);
-                    featureOp.rejected(uidState.state, flags);
+                    attributedOp.rejected(uidState.state, flags);
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
                     return mode;
                 }
             }
-            if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
-                    + " package " + packageName + (featureId == null ? "" : "." + featureId));
-            featureOp.accessed(proxyUid, proxyPackageName, proxyFeatureId, uidState.state, flags);
+            if (DEBUG) {
+                Slog.d(TAG,
+                        "noteOperation: allowing code " + code + " uid " + uid + " package "
+                                + packageName + (attributionTag == null ? ""
+                                : "." + attributionTag));
+            }
+            attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
+                    flags);
             scheduleOpNotedIfNeededLocked(code, uid, packageName,
                     AppOpsManager.MODE_ALLOWED);
 
             if (shouldCollectAsyncNotedOp) {
-                collectAsyncNotedOp(uid, packageName, code, featureId, message);
+                collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
             }
 
             return AppOpsManager.MODE_ALLOWED;
         }
     }
 
-    // TODO moltmann: Allow watching for feature ops
+    // TODO moltmann: Allow watching for attribution ops
     @Override
     public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
         int watchedUid = -1;
@@ -3131,11 +3170,11 @@
      * @param uid The uid the op was noted for
      * @param packageName The package the op was noted for
      * @param opCode The code of the op noted
-     * @param featureId The id of the feature to op was noted for
+     * @param attributionTag attribution tag the op was noted for
      * @param message The message for the op noting
      */
     private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
-            @Nullable String featureId, @NonNull String message) {
+            @Nullable String attributionTag, @NonNull String message) {
         Objects.requireNonNull(message);
 
         int callingUid = Binder.getCallingUid();
@@ -3147,10 +3186,10 @@
 
                 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
                 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
-                        featureId, message, System.currentTimeMillis());
+                        attributionTag, message, System.currentTimeMillis());
                 final boolean[] wasNoteForwarded = {false};
 
-                reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, featureId,
+                reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, attributionTag,
                         message);
 
                 if (callbacks != null) {
@@ -3161,7 +3200,7 @@
                         } catch (RemoteException e) {
                             Slog.e(TAG,
                                     "Could not forward noteOp of " + opCode + " to " + packageName
-                                            + "/" + uid + "(" + featureId + ")", e);
+                                            + "/" + uid + "(" + attributionTag + ")", e);
                         }
                     });
                 }
@@ -3263,7 +3302,7 @@
 
     @Override
     public int startOperation(IBinder clientId, int code, int uid, String packageName,
-            String featureId, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+            String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
             String message) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
@@ -3274,14 +3313,14 @@
 
         RestrictionBypass bypass;
         try {
-            bypass = verifyAndGetBypass(uid, packageName, featureId);
+            bypass = verifyAndGetBypass(uid, packageName, attributionTag);
         } catch (SecurityException e) {
             Slog.e(TAG, "startOperation", e);
             return AppOpsManager.MODE_ERRORED;
         }
 
         synchronized (this) {
-            final Ops ops = getOpsLocked(uid, resolvedPackageName, featureId, bypass,
+            final Ops ops = getOpsLocked(uid, resolvedPackageName, attributionTag, bypass,
                     true /* edit */);
             if (ops == null) {
                 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
@@ -3292,7 +3331,7 @@
             if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
                 return AppOpsManager.MODE_IGNORED;
             }
-            final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
+            final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
             final int switchCode = AppOpsManager.opToSwitch(code);
             final UidState uidState = ops.uidState;
             // If there is a non-default per UID policy (we set UID op mode only if
@@ -3305,7 +3344,7 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + resolvedPackageName);
-                    featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
+                    attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
                     return uidMode;
                 }
             } else {
@@ -3317,21 +3356,21 @@
                     if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + resolvedPackageName);
-                    featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
+                    attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
                     return mode;
                 }
             }
             if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
                     + " package " + resolvedPackageName);
             try {
-                featureOp.started(clientId, uidState.state);
+                attributedOp.started(clientId, uidState.state);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
         }
 
         if (shouldCollectAsyncNotedOp) {
-            collectAsyncNotedOp(uid, packageName, code, featureId, message);
+            collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
         }
 
         return AppOpsManager.MODE_ALLOWED;
@@ -3339,7 +3378,7 @@
 
     @Override
     public void finishOperation(IBinder clientId, int code, int uid, String packageName,
-            String featureId) {
+            String attributionTag) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -3349,27 +3388,31 @@
 
         RestrictionBypass bypass;
         try {
-            bypass = verifyAndGetBypass(uid, packageName, featureId);
+            bypass = verifyAndGetBypass(uid, packageName, attributionTag);
         } catch (SecurityException e) {
             Slog.e(TAG, "Cannot finishOperation", e);
             return;
         }
 
         synchronized (this) {
-            Op op = getOpLocked(code, uid, resolvedPackageName, featureId, bypass, true);
+            Op op = getOpLocked(code, uid, resolvedPackageName, attributionTag, bypass, true);
             if (op == null) {
+                Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
+                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
                 return;
             }
-            final FeatureOp featureOp = op.mFeatures.get(featureId);
-            if (featureOp == null) {
+            final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
+            if (attributedOp == null) {
+                Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
+                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
                 return;
             }
 
-            try {
-                featureOp.finished(clientId);
-            } catch (IllegalStateException e) {
-                Slog.e(TAG, "Operation not started: uid=" + uid + " pkg="
-                        + packageName + " op=" + AppOpsManager.opToName(code), e);
+            if (attributedOp.isRunning()) {
+                attributedOp.finished(clientId);
+            } else {
+                Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
+                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
             }
         }
     }
@@ -3636,25 +3679,25 @@
      *
      * @param uid The uid the package belongs to
      * @param packageName The package the might belong to the uid
-     * @param featureId The feature in the package or {@code null} if no need to verify
+     * @param attributionTag attribution tag or {@code null} if no need to verify
      *
      * @return {@code true} iff the package is privileged
      */
     private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
-            @Nullable String featureId) {
+            @Nullable String attributionTag) {
         if (uid == Process.ROOT_UID) {
             // For backwards compatibility, don't check package name for root UID.
             return null;
         }
 
-        // Do not check if uid/packageName/featureId is already known
+        // Do not check if uid/packageName/attributionTag is already known
         synchronized (this) {
             UidState uidState = mUidStates.get(uid);
             if (uidState != null && uidState.pkgOps != null) {
                 Ops ops = uidState.pkgOps.get(packageName);
 
-                if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))
-                        && ops.bypass != null) {
+                if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
+                        attributionTag)) && ops.bypass != null) {
                     return ops.bypass;
                 }
             }
@@ -3666,17 +3709,17 @@
             int pkgUid;
             AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage(
                     packageName);
-            boolean isFeatureIdValid = false;
+            boolean isAttributionTagValid = false;
 
             if (pkg != null) {
-                if (featureId == null) {
-                    isFeatureIdValid = true;
+                if (attributionTag == null) {
+                    isAttributionTagValid = true;
                 } else {
-                    if (pkg.getFeatures() != null) {
-                        int numFeatures = pkg.getFeatures().size();
-                        for (int i = 0; i < numFeatures; i++) {
-                            if (pkg.getFeatures().get(i).id.equals(featureId)) {
-                                isFeatureIdValid = true;
+                    if (pkg.getAttributions() != null) {
+                        int numAttributions = pkg.getAttributions().size();
+                        for (int i = 0; i < numAttributions; i++) {
+                            if (pkg.getAttributions().get(i).tag.equals(attributionTag)) {
+                                isAttributionTagValid = true;
                             }
                         }
                     }
@@ -3686,8 +3729,8 @@
                         UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
                 bypass = getBypassforPackage(pkg);
             } else {
-                // Allow any feature id for resolvable uids
-                isFeatureIdValid = true;
+                // Allow any attribution tag for resolvable uids
+                isAttributionTagValid = true;
 
                 pkgUid = resolveUid(packageName);
                 if (pkgUid >= 0) {
@@ -3699,9 +3742,9 @@
                         + " but it is really " + pkgUid);
             }
 
-            if (!isFeatureIdValid) {
+            if (!isAttributionTagValid) {
                 // TODO moltmann: Switch from logging to enforcement
-                Slog.e(TAG, "featureId " + featureId + " not declared in manifest of "
+                Slog.e(TAG, "attributionTag " + attributionTag + " not declared in manifest of "
                         + packageName);
             }
         } finally {
@@ -3716,13 +3759,13 @@
      *
      * @param uid The uid the package belongs to
      * @param packageName The name of the package
-     * @param featureId The feature in the package
+     * @param attributionTag attribution tag
      * @param bypass When to bypass certain op restrictions (can be null if edit == false)
      * @param edit If an ops does not exist, create the ops?
 
      * @return The ops
      */
-    private Ops getOpsLocked(int uid, String packageName, @Nullable String featureId,
+    private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
             @Nullable RestrictionBypass bypass, boolean edit) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
@@ -3750,8 +3793,8 @@
                 ops.bypass = bypass;
             }
 
-            if (featureId != null) {
-                ops.knownFeatureIds.add(featureId);
+            if (attributionTag != null) {
+                ops.knownAttributionTags.add(attributionTag);
             }
         }
 
@@ -3780,15 +3823,15 @@
      * @param code The code of the op
      * @param uid The uid the of the package
      * @param packageName The package name for which to get the state for
-     * @param featureId The feature in the package
+     * @param attributionTag The attribution tag
      * @param bypass When to bypass certain op restrictions (can be null if edit == false)
      * @param edit Iff {@code true} create the {@link Op} object if not yet created
      *
      * @return The {@link Op state} of the op
      */
     private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
-            @Nullable String featureId, @Nullable RestrictionBypass bypass, boolean edit) {
-        Ops ops = getOpsLocked(uid, packageName, featureId, bypass, edit);
+            @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) {
+        Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit);
         if (ops == null) {
             return null;
         }
@@ -4045,9 +4088,9 @@
         uidState.evalForegroundOps(mOpModeWatchers);
     }
 
-    private void readFeatureOp(XmlPullParser parser, @NonNull Op parent,
-            @Nullable String feature) throws NumberFormatException, IOException {
-        final FeatureOp featureOp = parent.getOrCreateFeature(parent, feature);
+    private void readAttributionOp(XmlPullParser parser, @NonNull Op parent,
+            @Nullable String attribution) throws NumberFormatException, IOException {
+        final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
 
         final long key = XmlUtils.readLongAttribute(parser, "n");
         final int uidState = extractUidStateFromKey(key);
@@ -4058,14 +4101,14 @@
         final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
         final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
         final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
-        final String proxyFeatureId = XmlUtils.readStringAttribute(parser, "pc");
+        final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
 
         if (accessTime > 0) {
-            featureOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg, proxyFeatureId,
-                    uidState, opFlags);
+            attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
+                    proxyAttributionTag, uidState, opFlags);
         }
         if (rejectTime > 0) {
-            featureOp.rejected(rejectTime, uidState, opFlags);
+            attributedOp.rejected(rejectTime, uidState, opFlags);
         }
     }
 
@@ -4091,7 +4134,7 @@
             }
             String tagName = parser.getName();
             if (tagName.equals("st")) {
-                readFeatureOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
+                readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
             } else {
                 Slog.w(TAG, "Unknown element under <op>: "
                         + parser.getName());
@@ -4205,11 +4248,11 @@
                                 out.attribute(null, "m", Integer.toString(op.getMode()));
                             }
 
-                            for (String featureId : op.getFeatures().keySet()) {
-                                final OpFeatureEntry feature = op.getFeatures().get(
-                                        featureId);
+                            for (String attributionTag : op.getAttributedOpEntries().keySet()) {
+                                final AttributedOpEntry attribution =
+                                        op.getAttributedOpEntries().get(attributionTag);
 
-                                final ArraySet<Long> keys = feature.collectKeys();
+                                final ArraySet<Long> keys = attribution.collectKeys();
 
                                 final int keyCount = keys.size();
                                 for (int k = 0; k < keyCount; k++) {
@@ -4218,14 +4261,14 @@
                                     final int uidState = AppOpsManager.extractUidStateFromKey(key);
                                     final int flags = AppOpsManager.extractFlagsFromKey(key);
 
-                                    final long accessTime = feature.getLastAccessTime(uidState,
+                                    final long accessTime = attribution.getLastAccessTime(uidState,
                                             uidState, flags);
-                                    final long rejectTime = feature.getLastRejectTime(uidState,
+                                    final long rejectTime = attribution.getLastRejectTime(uidState,
                                             uidState, flags);
-                                    final long accessDuration = feature.getLastDuration(uidState,
-                                            uidState, flags);
+                                    final long accessDuration = attribution.getLastDuration(
+                                            uidState, uidState, flags);
                                     // Proxy information for rejections is not backed up
-                                    final OpEventProxyInfo proxy = feature.getLastProxyInfo(
+                                    final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
                                             uidState, uidState, flags);
 
                                     if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
@@ -4234,17 +4277,17 @@
                                     }
 
                                     String proxyPkg = null;
-                                    String proxyFeatureId = null;
+                                    String proxyAttributionTag = null;
                                     int proxyUid = Process.INVALID_UID;
                                     if (proxy != null) {
                                         proxyPkg = proxy.getPackageName();
-                                        proxyFeatureId = proxy.getFeatureId();
+                                        proxyAttributionTag = proxy.getAttributionTag();
                                         proxyUid = proxy.getUid();
                                     }
 
                                     out.startTag(null, "st");
-                                    if (featureId != null) {
-                                        out.attribute(null, "id", featureId);
+                                    if (attributionTag != null) {
+                                        out.attribute(null, "id", attributionTag);
                                     }
                                     out.attribute(null, "n", Long.toString(key));
                                     if (accessTime > 0) {
@@ -4259,8 +4302,8 @@
                                     if (proxyPkg != null) {
                                         out.attribute(null, "pp", proxyPkg);
                                     }
-                                    if (proxyFeatureId != null) {
-                                        out.attribute(null, "pc", proxyFeatureId);
+                                    if (proxyAttributionTag != null) {
+                                        out.attribute(null, "pc", proxyAttributionTag);
                                     }
                                     if (proxyUid >= 0) {
                                         out.attribute(null, "pu", Integer.toString(proxyUid));
@@ -4294,7 +4337,7 @@
 
         int userId = UserHandle.USER_SYSTEM;
         String packageName;
-        String featureId;
+        String attributionTag;
         String opStr;
         String modeStr;
         int op;
@@ -4396,8 +4439,8 @@
                     userId = UserHandle.parseUserArg(getNextArgRequired());
                 } else if ("--uid".equals(argument)) {
                     targetsUid = true;
-                } else if ("--feature".equals(argument)) {
-                    featureId = getNextArgRequired();
+                } else if ("--attribution".equals(argument)) {
+                    attributionTag = getNextArgRequired();
                 } else {
                     if (packageName == null) {
                         packageName = argument;
@@ -4492,13 +4535,16 @@
         pw.println("AppOps service (appops) commands:");
         pw.println("  help");
         pw.println("    Print this help text.");
-        pw.println("  start [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
+        pw.println("  start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
+                + "<OP> ");
         pw.println("    Starts a given operation for a particular application.");
-        pw.println("  stop [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
+        pw.println("  stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
+                + "<OP> ");
         pw.println("    Stops a given operation for a particular application.");
         pw.println("  set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
         pw.println("    Set the mode for a particular application and operation.");
-        pw.println("  get [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> [<OP>]");
+        pw.println("  get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
+                + "[<OP>]");
         pw.println("    Return the mode for a particular application and optional operation.");
         pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
         pw.println("    Print all packages that currently have the given op in the given mode.");
@@ -4512,8 +4558,8 @@
         pw.println("    <PACKAGE> an Android package name or its UID if prefixed by --uid");
         pw.println("    <OP>      an AppOps operation.");
         pw.println("    <MODE>    one of allow, ignore, deny, or default");
-        pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
-        pw.println("              specified, the current user is assumed.");
+        pw.println("    <USER_ID> the user id under which the package is installed. If --user is");
+        pw.println("              not specified, the current user is assumed.");
     }
 
     static int onShellCommand(Shell shell, String cmd) {
@@ -4602,7 +4648,7 @@
                             pw.print(AppOpsManager.opToName(ent.getOp()));
                             pw.print(": ");
                             pw.print(AppOpsManager.modeToName(ent.getMode()));
-                            if (shell.featureId == null) {
+                            if (shell.attributionTag == null) {
                                 if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
                                     pw.print("; time=");
                                     TimeUtils.formatDuration(
@@ -4622,29 +4668,30 @@
                                     TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
                                 }
                             } else {
-                                final OpFeatureEntry featureEnt = ent.getFeatures().get(
-                                        shell.featureId);
-                                if (featureEnt != null) {
-                                    if (featureEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
+                                final AppOpsManager.AttributedOpEntry attributionEnt =
+                                        ent.getAttributedOpEntries().get(shell.attributionTag);
+                                if (attributionEnt != null) {
+                                    if (attributionEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
                                         pw.print("; time=");
-                                        TimeUtils.formatDuration(now - featureEnt.getLastAccessTime(
-                                                OP_FLAGS_ALL), pw);
+                                        TimeUtils.formatDuration(
+                                                now - attributionEnt.getLastAccessTime(
+                                                        OP_FLAGS_ALL), pw);
                                         pw.print(" ago");
                                     }
-                                    if (featureEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
+                                    if (attributionEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
                                         pw.print("; rejectTime=");
                                         TimeUtils.formatDuration(
-                                                now - featureEnt.getLastRejectTime(OP_FLAGS_ALL),
-                                                pw);
+                                                now - attributionEnt.getLastRejectTime(
+                                                        OP_FLAGS_ALL), pw);
                                         pw.print(" ago");
                                     }
-                                    if (featureEnt.isRunning()) {
+                                    if (attributionEnt.isRunning()) {
                                         pw.print(" (running)");
-                                    } else if (featureEnt.getLastDuration(OP_FLAGS_ALL)
+                                    } else if (attributionEnt.getLastDuration(OP_FLAGS_ALL)
                                             != -1) {
                                         pw.print("; duration=");
                                         TimeUtils.formatDuration(
-                                                featureEnt.getLastDuration(OP_FLAGS_ALL), pw);
+                                                attributionEnt.getLastDuration(OP_FLAGS_ALL), pw);
                                     }
                                 }
                             }
@@ -4752,7 +4799,7 @@
 
                     if (shell.packageName != null) {
                         shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
-                                shell.packageName, shell.featureId, true, true,
+                                shell.packageName, shell.attributionTag, true, true,
                                 "appops start shell command");
                     } else {
                         return -1;
@@ -4766,8 +4813,8 @@
                     }
 
                     if (shell.packageName != null) {
-                        shell.mInterface.finishOperation(shell.mToken,
-                                shell.op, shell.packageUid, shell.packageName, shell.featureId);
+                        shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid,
+                                shell.packageName, shell.attributionTag);
                     } else {
                         return -1;
                     }
@@ -4792,35 +4839,35 @@
         pw.println("    Limit output to data associated with the given app op mode.");
         pw.println("  --package [PACKAGE]");
         pw.println("    Limit output to data associated with the given package name.");
-        pw.println("  --featureId [featureId]");
-        pw.println("    Limit output to data associated with the given feature id.");
+        pw.println("  --attributionTag [attributionTag]");
+        pw.println("    Limit output to data associated with the given attribution tag.");
         pw.println("  --watchers");
         pw.println("    Only output the watcher sections.");
     }
 
-    private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterFeatureId,
+    private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
             @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
             @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
-        final int numFeatures = op.mFeatures.size();
-        for (int i = 0; i < numFeatures; i++) {
-            if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(op.mFeatures.keyAt(i),
-                    filterFeatureId)) {
+        final int numAttributions = op.mAttributions.size();
+        for (int i = 0; i < numAttributions; i++) {
+            if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
+                    op.mAttributions.keyAt(i), filterAttributionTag)) {
                 continue;
             }
 
-            pw.print(prefix + op.mFeatures.keyAt(i) + "=[\n");
-            dumpStatesLocked(pw, nowElapsed, op, op.mFeatures.keyAt(i), now, sdf, date,
+            pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
+            dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
                     prefix + "  ");
             pw.print(prefix + "]\n");
         }
     }
 
     private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
-            @Nullable String featureId, long now, @NonNull SimpleDateFormat sdf,
+            @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
             @NonNull Date date, @NonNull String prefix) {
 
-        final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
-                featureId).getFeatures().get(featureId);
+        final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
+                attributionTag).getAttributedOpEntries().get(attributionTag);
 
         final ArraySet<Long> keys = entry.collectKeys();
 
@@ -4837,11 +4884,11 @@
             final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
 
             String proxyPkg = null;
-            String proxyFeatureId = null;
+            String proxyAttributionTag = null;
             int proxyUid = Process.INVALID_UID;
             if (proxy != null) {
                 proxyPkg = proxy.getPackageName();
-                proxyFeatureId = proxy.getFeatureId();
+                proxyAttributionTag = proxy.getAttributionTag();
                 proxyUid = proxy.getUid();
             }
 
@@ -4865,8 +4912,8 @@
                     pw.print(proxyUid);
                     pw.print(", pkg=");
                     pw.print(proxyPkg);
-                    pw.print(", feature=");
-                    pw.print(proxyFeatureId);
+                    pw.print(", attributionTag=");
+                    pw.print(proxyAttributionTag);
                     pw.print("]");
                 }
                 pw.println();
@@ -4887,21 +4934,21 @@
                     pw.print(proxyUid);
                     pw.print(", pkg=");
                     pw.print(proxyPkg);
-                    pw.print(", feature=");
-                    pw.print(proxyFeatureId);
+                    pw.print(", attributionTag=");
+                    pw.print(proxyAttributionTag);
                     pw.print("]");
                 }
                 pw.println();
             }
         }
 
-        final FeatureOp featureOp = op.mFeatures.get(featureId);
-        if (featureOp.isRunning()) {
+        final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
+        if (attributedOp.isRunning()) {
             long earliestElapsedTime = Long.MAX_VALUE;
             long maxNumStarts = 0;
-            int numInProgressEvents = featureOp.mInProgressEvents.size();
+            int numInProgressEvents = attributedOp.mInProgressEvents.size();
             for (int i = 0; i < numInProgressEvents; i++) {
-                InProgressStartOpEvent event = featureOp.mInProgressEvents.valueAt(i);
+                InProgressStartOpEvent event = attributedOp.mInProgressEvents.valueAt(i);
 
                 earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
                 maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
@@ -4924,7 +4971,7 @@
 
         int dumpOp = OP_NONE;
         String dumpPackage = null;
-        String dumpFeatureId = null;
+        String dumpAttributionTag = null;
         int dumpUid = Process.INVALID_UID;
         int dumpMode = -1;
         boolean dumpWatchers = false;
@@ -4971,14 +5018,14 @@
                     }
                     dumpUid = UserHandle.getAppId(dumpUid);
                     dumpFilter |= FILTER_BY_UID;
-                } else if ("--featureId".equals(arg)) {
+                } else if ("--attributionTag".equals(arg)) {
                     i++;
                     if (i >= args.length) {
-                        pw.println("No argument for --featureId option");
+                        pw.println("No argument for --attributionTag option");
                         return;
                     }
-                    dumpFeatureId = args[i];
-                    dumpFilter |= FILTER_BY_FEATURE_ID;
+                    dumpAttributionTag = args[i];
+                    dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
                 } else if ("--mode".equals(arg)) {
                     i++;
                     if (i >= args.length) {
@@ -5317,8 +5364,8 @@
                             pw.print("="); pw.print(AppOpsManager.modeToName(mode));
                         }
                         pw.println("): ");
-                        dumpStatesLocked(pw, dumpFeatureId, dumpFilter, nowElapsed, op, now, sdf,
-                                date, "        ");
+                        dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
+                                sdf, date, "        ");
                     }
                 }
             }
@@ -5417,7 +5464,7 @@
 
         // Must not hold the appops lock
         if (dumpHistory && !dumpWatchers) {
-            mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpFeatureId, dumpOp,
+            mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
                     dumpFilter);
         }
     }
@@ -5522,7 +5569,7 @@
         if (resolvedPackageName == null) {
             return false;
         }
-        // TODO moltmann: Allow to check for feature op activeness
+        // TODO moltmann: Allow to check for attribution op activeness
         synchronized (AppOpsService.this) {
             Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false);
             if (pkgOps == null) {
@@ -5583,7 +5630,7 @@
      * Report runtime access to AppOp together with message (including stack trace)
      *
      * @param packageName The package which reported the op
-     * @param notedAppOp contains code of op and featureId provided by developer
+     * @param notedAppOp contains code of op and attributionTag provided by developer
      * @param message Message describing AppOp access (can be stack trace)
      *
      * @return Config for future sampling to reduce amount of reporting
@@ -5594,7 +5641,7 @@
         int uid = Binder.getCallingUid();
         Objects.requireNonNull(packageName);
         synchronized (this) {
-            switchPackageIfRarelyUsedLocked(packageName);
+            switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
             if (!packageName.equals(mSampledPackage)) {
                 return new MessageSamplingConfig(OP_NONE, 0,
                         Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
@@ -5605,7 +5652,7 @@
 
             reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName,
                     AppOpsManager.strOpToOp(notedAppOp.getOp()),
-                    notedAppOp.getFeatureId(), message);
+                    notedAppOp.getAttributionTag(), message);
 
             return new MessageSamplingConfig(mSampledAppOpCode, mAcceptableLeftDistance,
                     Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
@@ -5618,17 +5665,18 @@
      * @param uid Uid of the package which reported the op
      * @param packageName The package which reported the op
      * @param opCode Code of AppOp
-     * @param featureId FeautreId of AppOp reported
+     * @param attributionTag FeautreId of AppOp reported
      * @param message Message describing AppOp access (can be stack trace)
      */
     private void reportRuntimeAppOpAccessMessageAsyncLocked(int uid,
-            @NonNull String packageName, int opCode, @Nullable String featureId,
+            @NonNull String packageName, int opCode, @Nullable String attributionTag,
             @NonNull String message) {
-        switchPackageIfRarelyUsedLocked(packageName);
+        switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
         if (!Objects.equals(mSampledPackage, packageName)) {
             return;
         }
-        reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, featureId, message);
+        reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, attributionTag,
+                message);
     }
 
     /**
@@ -5636,7 +5684,7 @@
      * reporting uniformly at random across all received messages.
      */
     private void reportRuntimeAppOpAccessMessageInternalLocked(int uid,
-            @NonNull String packageName, int opCode, @Nullable String featureId,
+            @NonNull String packageName, int opCode, @Nullable String attributionTag,
             @NonNull String message) {
         int newLeftDistance = AppOpsManager.leftCircularDistance(opCode,
                 mSampledAppOpCode, _NUM_OP);
@@ -5653,7 +5701,7 @@
         mMessagesCollectedCount += 1.0f;
         if (ThreadLocalRandom.current().nextFloat() <= 1.0f / mMessagesCollectedCount) {
             mCollectedRuntimePermissionMessage = new RuntimeAppOpAccessMessage(uid, opCode,
-                    packageName, featureId, message, mSamplingStrategy);
+                    packageName, attributionTag, message, mSamplingStrategy);
         }
         return;
     }
@@ -5674,11 +5722,16 @@
 
     /**
      * Checks if package is in the list of rarely used package and starts watching the new package
-     * to collect incoming message.
+     * to collect incoming message or if collection is happening in first minutes since boot.
      * @param packageName
      */
-    private void switchPackageIfRarelyUsedLocked(@NonNull String packageName) {
-        if (mRarelyUsedPackages.contains(packageName)) {
+    private void switchPackageIfBootTimeOrRarelyUsedLocked(@NonNull String packageName) {
+        if (mSampledPackage == null) {
+            if (ThreadLocalRandom.current().nextFloat() < 0.1f) {
+                mSamplingStrategy = SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
+                resampleAppOpForPackageLocked(packageName);
+            }
+        } else if (mRarelyUsedPackages.contains(packageName)) {
             mRarelyUsedPackages.remove(packageName);
             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
                 mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
@@ -5740,6 +5793,10 @@
                             }
                         }
                         synchronized (this) {
+                            int numPkgs = mRarelyUsedPackages.size();
+                            for (int i = 0; i < numPkgs; i++) {
+                                candidates.add(mRarelyUsedPackages.valueAt(i));
+                            }
                             mRarelyUsedPackages = candidates;
                         }
                     }
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index cd450d4..ed45069 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.appop;
 
-import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
 import static android.app.AppOpsManager.FILTER_BY_UID;
@@ -23,7 +23,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
-import android.app.AppOpsManager.HistoricalFeatureOps;
 import android.app.AppOpsManager.HistoricalMode;
 import android.app.AppOpsManager.HistoricalOp;
 import android.app.AppOpsManager.HistoricalOps;
@@ -282,7 +281,7 @@
     }
 
     void dump(String prefix, PrintWriter pw, int filterUid, @Nullable String filterPackage,
-            @Nullable String filterFeatureId, int filterOp,
+            @Nullable String filterAttributionTag, int filterOp,
             @HistoricalOpsRequestFilter int filter) {
         if (!isApiEnabled()) {
             return;
@@ -298,7 +297,7 @@
                 pw.println(AppOpsManager.historicalModeToString(mMode));
 
                 final StringDumpVisitor visitor = new StringDumpVisitor(prefix + "  ",
-                        pw, filterUid, filterPackage, filterFeatureId, filterOp, filter);
+                        pw, filterUid, filterPackage, filterAttributionTag, filterOp, filter);
                 final long nowMillis = System.currentTimeMillis();
 
                 // Dump in memory state first
@@ -338,7 +337,7 @@
     }
 
     void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
-            @Nullable String featureId, @Nullable String[] opNames,
+            @Nullable String attributionTag, @Nullable String[] opNames,
             @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
             @OpFlags int flags, @NonNull RemoteCallback callback) {
         if (!isApiEnabled()) {
@@ -354,7 +353,7 @@
                     return;
                 }
                 final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
-                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, featureId,
+                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
                         opNames, filter, beginTimeMillis, endTimeMillis, flags);
                 final Bundle payload = new Bundle();
                 payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
@@ -363,7 +362,7 @@
         }
     }
 
-    void getHistoricalOps(int uid, @NonNull String packageName, @Nullable String featureId,
+    void getHistoricalOps(int uid, @NonNull String packageName, @Nullable String attributionTag,
             @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
             long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
             @NonNull RemoteCallback callback) {
@@ -401,7 +400,7 @@
                         || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
                     // Some of the current batch falls into the query, so extract that.
                     final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
-                    currentOpsCopy.filter(uid, packageName, featureId, opNames, filter,
+                    currentOpsCopy.filter(uid, packageName, attributionTag, opNames, filter,
                             inMemoryAdjBeginTimeMillis, inMemoryAdjEndTimeMillis);
                     result.merge(currentOpsCopy);
                 }
@@ -421,7 +420,7 @@
                         - onDiskAndInMemoryOffsetMillis, 0);
                 final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
                         - onDiskAndInMemoryOffsetMillis, 0);
-                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, featureId,
+                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
                         opNames, filter, onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis, flags);
             }
 
@@ -436,7 +435,7 @@
     }
 
     void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
-            @Nullable String featureId, @UidState int uidState, @OpFlags int flags) {
+            @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -445,13 +444,13 @@
                 }
                 getUpdatedPendingHistoricalOpsMLocked(
                         System.currentTimeMillis()).increaseAccessCount(op, uid, packageName,
-                        featureId, uidState, flags, 1);
+                        attributionTag, uidState, flags, 1);
             }
         }
     }
 
     void incrementOpRejected(int op, int uid, @NonNull String packageName,
-            @Nullable String featureId, @UidState int uidState, @OpFlags int flags) {
+            @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -460,13 +459,13 @@
                 }
                 getUpdatedPendingHistoricalOpsMLocked(
                         System.currentTimeMillis()).increaseRejectCount(op, uid, packageName,
-                        featureId, uidState, flags, 1);
+                        attributionTag, uidState, flags, 1);
             }
         }
     }
 
     void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
-            @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+            @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
             long increment) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
@@ -476,7 +475,7 @@
                 }
                 getUpdatedPendingHistoricalOpsMLocked(
                         System.currentTimeMillis()).increaseAccessDuration(op, uid, packageName,
-                        featureId, uidState, flags, increment);
+                        attributionTag, uidState, flags, increment);
             }
         }
     }
@@ -728,7 +727,7 @@
         private static final String TAG_OPS = "ops";
         private static final String TAG_UID = "uid";
         private static final String TAG_PACKAGE = "pkg";
-        private static final String TAG_FEATURE = "ftr";
+        private static final String TAG_ATTRIBUTION = "ftr";
         private static final String TAG_OP = "op";
         private static final String TAG_STATE = "st";
 
@@ -807,9 +806,9 @@
 
         @Nullable List<HistoricalOps> readHistoryRawDLocked() {
             return collectHistoricalOpsBaseDLocked(Process.INVALID_UID /*filterUid*/,
-                    null /*filterPackageName*/, null /*filterFeatureId*/, null /*filterOpNames*/,
-                    0 /*filter*/, 0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/,
-                    AppOpsManager.OP_FLAGS_ALL);
+                    null /*filterPackageName*/, null /*filterAttributionTag*/,
+                    null /*filterOpNames*/, 0 /*filter*/, 0 /*filterBeginTimeMills*/,
+                    Long.MAX_VALUE /*filterEndTimeMills*/, AppOpsManager.OP_FLAGS_ALL);
         }
 
         @Nullable List<HistoricalOps> readHistoryDLocked() {
@@ -861,13 +860,13 @@
             return 0;
         }
 
-        private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps,
-                int filterUid, @Nullable String filterPackageName, @Nullable String filterFeatureId,
+        private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps, int filterUid,
+                @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 long filterBeingMillis, long filterEndMillis, @OpFlags int filterFlags) {
             final List<HistoricalOps> readOps = collectHistoricalOpsBaseDLocked(filterUid,
-                    filterPackageName, filterFeatureId, filterOpNames, filter, filterBeingMillis,
-                    filterEndMillis, filterFlags);
+                    filterPackageName, filterAttributionTag, filterOpNames, filter,
+                    filterBeingMillis, filterEndMillis, filterFlags);
             if (readOps != null) {
                 final int readCount = readOps.size();
                 for (int i = 0; i < readCount; i++) {
@@ -877,8 +876,8 @@
              }
         }
 
-        private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(
-                int filterUid, @Nullable String filterPackageName, @Nullable String filterFeatureId,
+        private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(int filterUid,
+                @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags) {
             File baseDir = null;
@@ -892,7 +891,7 @@
                 final Set<String> historyFiles = getHistoricalFileNames(baseDir);
                 final long[] globalContentOffsetMillis = {0};
                 final LinkedList<HistoricalOps> ops = collectHistoricalOpsRecursiveDLocked(
-                        baseDir, filterUid, filterPackageName, filterFeatureId, filterOpNames,
+                        baseDir, filterUid, filterPackageName, filterAttributionTag, filterOpNames,
                         filter, filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
                         globalContentOffsetMillis, null /*outOps*/, 0 /*depth*/, historyFiles);
                 if (DEBUG) {
@@ -909,7 +908,7 @@
 
         private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsRecursiveDLocked(
                 @NonNull File baseDir, int filterUid, @Nullable String filterPackageName,
-                @Nullable String filterFeatureId, @Nullable String[] filterOpNames,
+                @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
                 @HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
                 long filterEndTimeMillis, @OpFlags int filterFlags,
                 @NonNull long[] globalContentOffsetMillis,
@@ -927,7 +926,7 @@
             // Read historical data at this level
             final List<HistoricalOps> readOps = readHistoricalOpsLocked(baseDir,
                     previousIntervalEndMillis, currentIntervalEndMillis, filterUid,
-                    filterPackageName, filterFeatureId, filterOpNames, filter,
+                    filterPackageName, filterAttributionTag, filterOpNames, filter,
                     filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
                     globalContentOffsetMillis, depth, historyFiles);
             // Empty is a special signal to stop diving
@@ -937,7 +936,7 @@
 
             // Collect older historical data from subsequent levels
             outOps = collectHistoricalOpsRecursiveDLocked(baseDir, filterUid, filterPackageName,
-                    filterFeatureId, filterOpNames, filter, filterBeginTimeMillis,
+                    filterAttributionTag, filterOpNames, filter, filterBeginTimeMillis,
                     filterEndTimeMillis, filterFlags, globalContentOffsetMillis, outOps, depth + 1,
                     historyFiles);
 
@@ -1006,7 +1005,7 @@
             final List<HistoricalOps> existingOps = readHistoricalOpsLocked(oldBaseDir,
                     previousIntervalEndMillis, currentIntervalEndMillis,
                     Process.INVALID_UID /*filterUid*/, null /*filterPackageName*/,
-                    null /*filterFeatureId*/, null /*filterOpNames*/, 0 /*filter*/,
+                    null /*filterAttributionTag*/, null /*filterOpNames*/, 0 /*filter*/,
                     Long.MIN_VALUE /*filterBeginTimeMillis*/,
                     Long.MAX_VALUE /*filterEndTimeMillis*/, AppOpsManager.OP_FLAGS_ALL, null, depth,
                     null /*historyFiles*/);
@@ -1120,7 +1119,7 @@
 
         private @Nullable List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
                 long intervalBeginMillis, long intervalEndMillis, int filterUid,
-                @Nullable String filterPackageName, @Nullable String filterFeatureId,
+                @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags,
                 @Nullable long[] cumulativeOverflowMillis, int depth,
@@ -1147,15 +1146,16 @@
                     return null;
                 }
             }
-            return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterFeatureId,
+            return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterAttributionTag,
                     filterOpNames, filter, filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
                     cumulativeOverflowMillis);
         }
 
-        private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
-                int filterUid, @Nullable String filterPackageName, @Nullable String filterFeatureId,
-                @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
-                long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags,
+        private @Nullable  List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
+                int filterUid, @Nullable String filterPackageName,
+                @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
+                @HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
+                long filterEndTimeMillis, @OpFlags int filterFlags,
                 @Nullable long[] cumulativeOverflowMillis)
                 throws IOException, XmlPullParserException {
             if (DEBUG) {
@@ -1180,7 +1180,7 @@
                 while (XmlUtils.nextElementWithin(parser, depth)) {
                     if (TAG_OPS.equals(parser.getName())) {
                         final HistoricalOps ops = readeHistoricalOpsDLocked(parser, filterUid,
-                                filterPackageName, filterFeatureId, filterOpNames, filter,
+                                filterPackageName, filterAttributionTag, filterOpNames, filter,
                                 filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
                                 cumulativeOverflowMillis);
                         if (ops == null) {
@@ -1215,7 +1215,7 @@
 
         private @Nullable HistoricalOps readeHistoricalOpsDLocked(
                 @NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
-                @Nullable String filterFeatureId, @Nullable String[] filterOpNames,
+                @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
                 @HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
                 long filterEndTimeMillis, @OpFlags int filterFlags,
                 @Nullable long[] cumulativeOverflowMillis)
@@ -1245,8 +1245,8 @@
             while (XmlUtils.nextElementWithin(parser, depth)) {
                 if (TAG_UID.equals(parser.getName())) {
                     final HistoricalOps returnedOps = readHistoricalUidOpsDLocked(ops, parser,
-                            filterUid, filterPackageName, filterFeatureId, filterOpNames, filter,
-                            filterFlags, filterScale);
+                            filterUid, filterPackageName, filterAttributionTag, filterOpNames,
+                            filter, filterFlags, filterScale);
                     if (ops == null) {
                         ops = returnedOps;
                     }
@@ -1260,7 +1260,7 @@
 
         private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
                 @Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
-                @Nullable String filterPackageName, @Nullable String filterFeatureId,
+                @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 @OpFlags int filterFlags, double filterScale)
                 throws IOException, XmlPullParserException {
@@ -1272,8 +1272,8 @@
             final int depth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, depth)) {
                 if (TAG_PACKAGE.equals(parser.getName())) {
-                    final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops,
-                            uid, parser, filterPackageName, filterFeatureId, filterOpNames, filter,
+                    final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops, uid,
+                            parser, filterPackageName, filterAttributionTag, filterOpNames, filter,
                             filterFlags, filterScale);
                     if (ops == null) {
                         ops = returnedOps;
@@ -1285,7 +1285,7 @@
 
         private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
                 @Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
-                @Nullable String filterPackageName, @Nullable String filterFeatureId,
+                @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 @OpFlags int filterFlags, double filterScale)
                 throws IOException, XmlPullParserException {
@@ -1296,9 +1296,9 @@
             }
             final int depth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, depth)) {
-                if (TAG_FEATURE.equals(parser.getName())) {
-                    final HistoricalOps returnedOps = readHistoricalFeatureOpsDLocked(ops, uid,
-                            packageName, parser, filterFeatureId, filterOpNames, filter,
+                if (TAG_ATTRIBUTION.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalAttributionOpsDLocked(ops, uid,
+                            packageName, parser, filterAttributionTag, filterOpNames, filter,
                             filterFlags, filterScale);
                     if (ops == null) {
                         ops = returnedOps;
@@ -1308,15 +1308,15 @@
             return ops;
         }
 
-        private @Nullable HistoricalOps readHistoricalFeatureOpsDLocked(@Nullable HistoricalOps ops,
-                int uid, String packageName, @NonNull XmlPullParser parser,
-                @Nullable String filterFeatureId, @Nullable String[] filterOpNames,
-                @HistoricalOpsRequestFilter int filter, @OpFlags int filterFlags,
-                double filterScale)
+        private @Nullable HistoricalOps readHistoricalAttributionOpsDLocked(
+                @Nullable HistoricalOps ops, int uid, String packageName,
+                @NonNull XmlPullParser parser, @Nullable String filterAttributionTag,
+                @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
+                @OpFlags int filterFlags, double filterScale)
                 throws IOException, XmlPullParserException {
-            final String featureId = XmlUtils.readStringAttribute(parser, ATTR_NAME);
-            if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(filterFeatureId,
-                    featureId)) {
+            final String attributionTag = XmlUtils.readStringAttribute(parser, ATTR_NAME);
+            if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(filterAttributionTag,
+                    attributionTag)) {
                 XmlUtils.skipCurrentTag(parser);
                 return null;
             }
@@ -1324,7 +1324,8 @@
             while (XmlUtils.nextElementWithin(parser, depth)) {
                 if (TAG_OP.equals(parser.getName())) {
                     final HistoricalOps returnedOps = readHistoricalOpDLocked(ops, uid, packageName,
-                            featureId, parser, filterOpNames, filter, filterFlags, filterScale);
+                            attributionTag, parser, filterOpNames, filter, filterFlags,
+                            filterScale);
                     if (ops == null) {
                         ops = returnedOps;
                     }
@@ -1334,7 +1335,7 @@
         }
 
         private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
-                int uid, @NonNull String packageName, @Nullable String featureId,
+                int uid, @NonNull String packageName, @Nullable String attributionTag,
                 @NonNull XmlPullParser parser, @Nullable String[] filterOpNames,
                 @HistoricalOpsRequestFilter int filter, @OpFlags int filterFlags,
                 double filterScale)
@@ -1349,7 +1350,7 @@
             while (XmlUtils.nextElementWithin(parser, depth)) {
                 if (TAG_STATE.equals(parser.getName())) {
                     final HistoricalOps returnedOps = readStateDLocked(ops, uid,
-                            packageName, featureId, op, parser, filterFlags, filterScale);
+                            packageName, attributionTag, op, parser, filterFlags, filterScale);
                     if (ops == null) {
                         ops = returnedOps;
                     }
@@ -1359,7 +1360,7 @@
         }
 
         private @Nullable HistoricalOps readStateDLocked(@Nullable HistoricalOps ops,
-                int uid, @NonNull String packageName, @Nullable String featureId, int op,
+                int uid, @NonNull String packageName, @Nullable String attributionTag, int op,
                 @NonNull XmlPullParser parser, @OpFlags int filterFlags, double filterScale)
                 throws IOException {
             final long key = XmlUtils.readLongAttribute(parser, ATTR_NAME);
@@ -1377,7 +1378,7 @@
                 if (ops == null) {
                     ops = new HistoricalOps(0, 0);
                 }
-                ops.increaseAccessCount(op, uid, packageName, featureId, uidState, flags,
+                ops.increaseAccessCount(op, uid, packageName, attributionTag, uidState, flags,
                         accessCount);
             }
             long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
@@ -1389,7 +1390,7 @@
                 if (ops == null) {
                     ops = new HistoricalOps(0, 0);
                 }
-                ops.increaseRejectCount(op, uid, packageName, featureId, uidState, flags,
+                ops.increaseRejectCount(op, uid, packageName, attributionTag, uidState, flags,
                         rejectCount);
             }
             long accessDuration =  XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
@@ -1401,7 +1402,7 @@
                 if (ops == null) {
                     ops = new HistoricalOps(0, 0);
                 }
-                ops.increaseAccessDuration(op, uid, packageName, featureId, uidState, flags,
+                ops.increaseAccessDuration(op, uid, packageName, attributionTag, uidState, flags,
                         accessDuration);
             }
             return ops;
@@ -1467,24 +1468,25 @@
                 @NonNull XmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_PACKAGE);
             serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
-            final int numFeatures = packageOps.getFeatureCount();
-            for (int i = 0; i < numFeatures; i++) {
-                final HistoricalFeatureOps op = packageOps.getFeatureOpsAt(i);
-                writeHistoricalFeatureOpsDLocked(op, serializer);
+            final int numAttributions = packageOps.getAttributedOpsCount();
+            for (int i = 0; i < numAttributions; i++) {
+                final AppOpsManager.AttributedHistoricalOps op = packageOps.getAttributedOpsAt(i);
+                writeHistoricalAttributionOpsDLocked(op, serializer);
             }
             serializer.endTag(null, TAG_PACKAGE);
         }
 
-        private void writeHistoricalFeatureOpsDLocked(@NonNull HistoricalFeatureOps featureOps,
+        private void writeHistoricalAttributionOpsDLocked(
+                @NonNull AppOpsManager.AttributedHistoricalOps attributionOps,
                 @NonNull XmlSerializer serializer) throws IOException {
-            serializer.startTag(null, TAG_FEATURE);
-            XmlUtils.writeStringAttribute(serializer, ATTR_NAME, featureOps.getFeatureId());
-            final int opCount = featureOps.getOpCount();
+            serializer.startTag(null, TAG_ATTRIBUTION);
+            XmlUtils.writeStringAttribute(serializer, ATTR_NAME, attributionOps.getTag());
+            final int opCount = attributionOps.getOpCount();
             for (int i = 0; i < opCount; i++) {
-                final HistoricalOp op = featureOps.getOpAt(i);
+                final HistoricalOp op = attributionOps.getOpAt(i);
                 writeHistoricalOpDLocked(op, serializer);
             }
-            serializer.endTag(null, TAG_FEATURE);
+            serializer.endTag(null, TAG_ATTRIBUTION);
         }
 
         private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
@@ -1718,29 +1720,29 @@
         private final @NonNull String mOpsPrefix;
         private final @NonNull String mUidPrefix;
         private final @NonNull String mPackagePrefix;
-        private final @NonNull String mFeaturePrefix;
+        private final @NonNull String mAttributionPrefix;
         private final @NonNull String mEntryPrefix;
         private final @NonNull String mUidStatePrefix;
         private final @NonNull PrintWriter mWriter;
         private final int mFilterUid;
         private final String mFilterPackage;
-        private final String mFilterFeatureId;
+        private final String mFilterAttributionTag;
         private final int mFilterOp;
         private final @HistoricalOpsRequestFilter int mFilter;
 
         StringDumpVisitor(@NonNull String prefix, @NonNull PrintWriter writer, int filterUid,
-                @Nullable String filterPackage, @Nullable String filterFeatureId, int filterOp,
+                @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp,
                 @HistoricalOpsRequestFilter int filter) {
             mOpsPrefix = prefix + "  ";
             mUidPrefix = mOpsPrefix + "  ";
             mPackagePrefix = mUidPrefix + "  ";
-            mFeaturePrefix = mPackagePrefix + "  ";
-            mEntryPrefix = mFeaturePrefix + "  ";
+            mAttributionPrefix = mPackagePrefix + "  ";
+            mEntryPrefix = mAttributionPrefix + "  ";
             mUidStatePrefix = mEntryPrefix + "  ";
             mWriter = writer;
             mFilterUid = filterUid;
             mFilterPackage = filterPackage;
-            mFilterFeatureId = filterFeatureId;
+            mFilterAttributionTag = filterAttributionTag;
             mFilterOp = filterOp;
             mFilter = filter;
         }
@@ -1791,14 +1793,14 @@
         }
 
         @Override
-        public void visitHistoricalFeatureOps(HistoricalFeatureOps ops) {
-            if ((mFilter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(mFilterPackage,
-                    ops.getFeatureId())) {
+        public void visitHistoricalAttributionOps(AppOpsManager.AttributedHistoricalOps ops) {
+            if ((mFilter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(mFilterPackage,
+                    ops.getTag())) {
                 return;
             }
-            mWriter.print(mFeaturePrefix);
-            mWriter.print("Feature ");
-            mWriter.print(ops.getFeatureId());
+            mWriter.print(mAttributionPrefix);
+            mWriter.print("Attribution ");
+            mWriter.print(ops.getTag());
             mWriter.println(":");
         }
 
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index ecdafb0..e7c09ba 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -24,6 +24,7 @@
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.UserSwitchObserver;
@@ -296,7 +297,7 @@
                 }
 
                 case MSG_ON_DISMISSED: {
-                    handleOnDismissed(msg.arg1);
+                    handleOnDismissed(msg.arg1, (byte[]) msg.obj);
                     break;
                 }
 
@@ -611,8 +612,12 @@
         }
 
         @Override
-        public void onDialogDismissed(int reason) throws RemoteException {
-            mHandler.obtainMessage(MSG_ON_DISMISSED, reason, 0 /* arg2 */).sendToTarget();
+        public void onDialogDismissed(int reason, @Nullable byte[] credentialAttestation)
+                throws RemoteException {
+            mHandler.obtainMessage(MSG_ON_DISMISSED,
+                    reason,
+                    0 /* arg2 */,
+                    credentialAttestation /* obj */).sendToTarget();
         }
 
         @Override
@@ -1422,7 +1427,8 @@
                                 0 /* biometricModality */,
                                 false /* requireConfirmation */,
                                 mCurrentAuthSession.mUserId,
-                                mCurrentAuthSession.mOpPackageName);
+                                mCurrentAuthSession.mOpPackageName,
+                                mCurrentAuthSession.mSessionId);
                     } else {
                         mPendingAuthSession.mClientReceiver.onError(modality, error, vendorCode);
                         mPendingAuthSession = null;
@@ -1458,7 +1464,7 @@
         }
     }
 
-    private void handleOnDismissed(int reason) {
+    private void handleOnDismissed(int reason, @Nullable byte[] credentialAttestation) {
         if (mCurrentAuthSession == null) {
             Slog.e(TAG, "onDismissed: " + reason + ", auth session null");
             return;
@@ -1469,6 +1475,7 @@
         try {
             switch (reason) {
                 case BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED:
+                    mKeyStore.addAuthToken(credentialAttestation);
                 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED:
                 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED:
                     if (mCurrentAuthSession.mTokenEscrow != null) {
@@ -1616,7 +1623,8 @@
                 try {
                     mStatusBarService.showAuthenticationDialog(mCurrentAuthSession.mBundle,
                             mInternalReceiver, modality, requireConfirmation, userId,
-                            mCurrentAuthSession.mOpPackageName);
+                            mCurrentAuthSession.mOpPackageName,
+                            mCurrentAuthSession.mSessionId);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Remote exception", e);
                 }
@@ -1701,7 +1709,8 @@
                         0 /* biometricModality */,
                         false /* requireConfirmation */,
                         mCurrentAuthSession.mUserId,
-                        mCurrentAuthSession.mOpPackageName);
+                        mCurrentAuthSession.mOpPackageName,
+                        sessionId);
             } else {
                 mPendingAuthSession.mState = STATE_AUTH_CALLED;
                 for (AuthenticatorWrapper authenticator : mAuthenticators) {
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 7bdeb59..2e9818d 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -151,6 +151,15 @@
         return true;
     }
 
+    /**
+     * Checks whether a change has an override for a package.
+     * @param packageName name of the package
+     * @return true if there is such override
+     */
+    boolean hasOverride(String packageName) {
+        return mPackageOverrides != null && mPackageOverrides.containsKey(packageName);
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("ChangeId(")
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index b2ea311..aeaa1fe 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -247,11 +247,13 @@
             CompatChange c = mChanges.get(changeId);
             try {
                 if (c != null) {
-                    OverrideAllowedState allowedState =
-                            mOverrideValidator.getOverrideAllowedState(changeId, packageName);
-                    allowedState.enforce(changeId, packageName);
-                    overrideExists = true;
-                    c.removePackageOverride(packageName);
+                    overrideExists = c.hasOverride(packageName);
+                    if (overrideExists) {
+                        OverrideAllowedState allowedState =
+                                mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+                        allowedState.enforce(changeId, packageName);
+                        c.removePackageOverride(packageName);
+                    }
                 }
             } catch (RemoteException e) {
                 // Should never occur, since validator is in the same process.
@@ -298,12 +300,14 @@
             for (int i = 0; i < mChanges.size(); ++i) {
                 try {
                     CompatChange change = mChanges.valueAt(i);
-                    OverrideAllowedState allowedState =
-                            mOverrideValidator.getOverrideAllowedState(change.getId(),
-                                                                       packageName);
-                    allowedState.enforce(change.getId(), packageName);
-                    if (change != null) {
-                        mChanges.valueAt(i).removePackageOverride(packageName);
+                    if (change.hasOverride(packageName)) {
+                        OverrideAllowedState allowedState =
+                                mOverrideValidator.getOverrideAllowedState(change.getId(),
+                                        packageName);
+                        allowedState.enforce(change.getId(), packageName);
+                        if (change != null) {
+                            mChanges.valueAt(i).removePackageOverride(packageName);
+                        }
                     }
                 } catch (RemoteException e) {
                     // Should never occur, since validator is in the same process.
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7c3cab1..20ffd9f 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2563,7 +2563,7 @@
         public void exitIfOuterInterfaceIs(String interfaze) {
             if (interfaze.equals(mOuterInterface)) {
                 Log.i(TAG, "Legacy VPN is going down with " + interfaze);
-                exit();
+                exitVpnRunner();
             }
         }
 
@@ -2572,6 +2572,10 @@
         public void exitVpnRunner() {
             // We assume that everything is reset after stopping the daemons.
             interrupt();
+
+            // Always disconnect. This may be called again in cleanupVpnStateLocked() if
+            // exitVpnRunner() was called from exit(), but it will be a no-op.
+            agentDisconnect();
             try {
                 mContext.unregisterReceiver(mBroadcastReceiver);
             } catch (IllegalArgumentException e) {}
@@ -2794,7 +2798,7 @@
             } catch (Exception e) {
                 Log.i(TAG, "Aborting", e);
                 updateState(DetailedState.FAILED, e.getMessage());
-                exit();
+                exitVpnRunner();
             }
         }
 
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 6da0de1..44ab438 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -50,6 +50,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
@@ -69,8 +70,11 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
@@ -85,6 +89,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /** Implementation of {@link AppIntegrityManagerService}. */
 public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
@@ -239,6 +245,11 @@
         return new ParceledListSlice<>(rules);
     }
 
+    @Override
+    public List<String> getWhitelistedRuleProviders() throws RemoteException {
+        return getAllowedRuleProviders();
+    }
+
     private void handleIntegrityVerification(Intent intent) {
         int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
 
@@ -467,8 +478,23 @@
         if (installationPath == null) {
             throw new IllegalArgumentException("Installation path is null, package not found");
         }
-        SourceStampVerificationResult sourceStampVerificationResult =
-                SourceStampVerifier.verify(installationPath.getAbsolutePath());
+
+        SourceStampVerificationResult sourceStampVerificationResult;
+        if (installationPath.isDirectory()) {
+            try (Stream<Path> filesList = Files.list(installationPath.toPath())) {
+                List<String> apkFiles =
+                        filesList
+                                .map(path -> path.toAbsolutePath().toString())
+                                .collect(Collectors.toList());
+                sourceStampVerificationResult = SourceStampVerifier.verify(apkFiles);
+            } catch (IOException e) {
+                throw new IllegalArgumentException("Could not read APK directory");
+            }
+        } else {
+            sourceStampVerificationResult =
+                    SourceStampVerifier.verify(installationPath.getAbsolutePath());
+        }
+
         appInstallMetadata.setIsStampPresent(sourceStampVerificationResult.isPresent());
         appInstallMetadata.setIsStampVerified(sourceStampVerificationResult.isVerified());
         // A verified stamp is set to be trusted.
diff --git a/services/core/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java
index b158388..682b104 100644
--- a/services/core/java/com/android/server/location/CountryDetectorBase.java
+++ b/services/core/java/com/android/server/location/CountryDetectorBase.java
@@ -31,7 +31,7 @@
  * @hide
  */
 public abstract class CountryDetectorBase {
-    private static final String FEATURE_ID = "CountryDetector";
+    private static final String ATTRIBUTION_TAG = "CountryDetector";
 
     protected final Handler mHandler;
     protected final Context mContext;
@@ -39,7 +39,7 @@
     protected Country mDetectedCountry;
 
     public CountryDetectorBase(Context context) {
-        mContext = context.createFeatureContext(FEATURE_ID);
+        mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mHandler = new Handler();
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 69a5b35..7b1003f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -931,6 +931,8 @@
                         .setType(MetricsEvent.TYPE_ACTION)
                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
+                mNotificationRecordLogger.log(
+                        NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, r);
                 EventLogTags.writeNotificationClicked(key,
                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
                         nv.rank, nv.count);
@@ -970,7 +972,8 @@
                                 generatedByAssistant ? 1 : 0)
                         .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
                                 nv.location.toMetricsEventEnum()));
-
+                mNotificationRecordLogger.log(
+                        NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED, r);
                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
                         nv.rank, nv.count);
@@ -1004,6 +1007,8 @@
         public void onPanelRevealed(boolean clearEffects, int items) {
             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
             MetricsLogger.histogram(getContext(), "note_load", items);
+            mNotificationRecordLogger.log(
+                    NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN);
             EventLogTags.writeNotificationPanelRevealed(items);
             if (clearEffects) {
                 clearEffects();
@@ -1014,6 +1019,8 @@
         @Override
         public void onPanelHidden() {
             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
+            mNotificationRecordLogger.log(
+                    NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE);
             EventLogTags.writeNotificationPanelHidden();
             mAssistants.onPanelHidden();
         }
@@ -1103,6 +1110,10 @@
                         MetricsLogger.action(r.getItemLogMaker()
                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
                                         : MetricsEvent.TYPE_COLLAPSE));
+                        mNotificationRecordLogger.log(
+                                NotificationRecordLogger.NotificationEvent.fromExpanded(expanded,
+                                        userAction),
+                                r);
                     }
                     if (expanded && userAction) {
                         r.recordExpanded();
@@ -1124,6 +1135,9 @@
                     mMetricsLogger.write(r.getLogMaker()
                             .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
                             .setType(MetricsEvent.TYPE_ACTION));
+                    mNotificationRecordLogger.log(
+                            NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
+                            r);
                     reportUserInteraction(r);
                     mAssistants.notifyAssistantNotificationDirectReplyLocked(r.getSbn());
                 }
@@ -1166,6 +1180,9 @@
                                     MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
                                     modifiedBeforeSending ? 1 : 0);
                     mMetricsLogger.write(logMaker);
+                    mNotificationRecordLogger.log(
+                            NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
+                            r);
                     // Treat clicking on a smart reply as a user interaction.
                     reportUserInteraction(r);
                     mAssistants.notifyAssistantSuggestedReplySent(
@@ -1310,6 +1327,9 @@
                             MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
                             r.getEditChoicesBeforeSending() ? 1 : 0);
             mMetricsLogger.write(logMaker);
+            mNotificationRecordLogger.log(
+                    NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLY_VISIBLE,
+                    r);
         }
     }
 
@@ -6150,6 +6170,9 @@
                 MetricsLogger.action(r.getLogMaker()
                         .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
                         .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
+                mNotificationRecordLogger.log(
+                        NotificationRecordLogger.NotificationEvent.NOTIFICATION_NOT_POSTED_SNOOZED,
+                        r);
                 if (DBG) {
                     Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
                 }
@@ -6279,6 +6302,8 @@
                             mDuration)
                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
                             mSnoozeCriterionId == null ? 0 : 1));
+            mNotificationRecordLogger.log(
+                    NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, r);
             reportUserInteraction(r);
             boolean wasPosted = removeFromNotificationListsLocked(r);
             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index f4ee461..6c833f96 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -34,11 +34,14 @@
 import java.util.Objects;
 
 /**
- * Interface for writing NotificationReported atoms to statsd log.
+ * Interface for writing NotificationReported atoms to statsd log. Use NotificationRecordLoggerImpl
+ * in production.  Use NotificationRecordLoggerFake for testing.
  * @hide
  */
 public interface NotificationRecordLogger {
 
+    // The high-level interface used by clients.
+
     /**
      * May log a NotificationReported atom reflecting the posting or update of a notification.
      * @param r The new NotificationRecord. If null, no action is taken.
@@ -57,9 +60,11 @@
      * @param reason The reason the notification was canceled.
      * @param dismissalSurface The surface the notification was dismissed from.
      */
-    void logNotificationCancelled(@Nullable NotificationRecord r,
+    default void logNotificationCancelled(@Nullable NotificationRecord r,
             @NotificationListenerService.NotificationCancelReason int reason,
-            @NotificationStats.DismissalSurface int dismissalSurface);
+            @NotificationStats.DismissalSurface int dismissalSurface) {
+        log(NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface), r);
+    }
 
     /**
      * Logs a notification visibility change event using UiEventReported (event ids from the
@@ -67,7 +72,17 @@
      * @param r The NotificationRecord. If null, no action is taken.
      * @param visible True if the notification became visible.
      */
-    void logNotificationVisibility(@Nullable NotificationRecord r, boolean visible);
+    default void logNotificationVisibility(@Nullable NotificationRecord r, boolean visible) {
+        log(NotificationEvent.fromVisibility(visible), r);
+    }
+
+    // The UiEventReported logging methods are implemented in terms of this lower-level interface.
+
+    /** Logs a UiEventReported event for the given notification. */
+    void log(UiEventLogger.UiEventEnum event, NotificationRecord r);
+
+    /** Logs a UiEventReported event that is not associated with any notification. */
+    void log(UiEventLogger.UiEventEnum event);
 
     /**
      * The UiEvent enums that this class can log.
@@ -204,7 +219,30 @@
         @UiEvent(doc = "Notification became visible.")
         NOTIFICATION_OPEN(197),
         @UiEvent(doc = "Notification stopped being visible.")
-        NOTIFICATION_CLOSE(198);
+        NOTIFICATION_CLOSE(198),
+        @UiEvent(doc = "Notification was snoozed.")
+        NOTIFICATION_SNOOZED(317),
+        @UiEvent(doc = "Notification was not posted because its app is snoozed.")
+        NOTIFICATION_NOT_POSTED_SNOOZED(319),
+        @UiEvent(doc = "Notification was clicked.")
+        NOTIFICATION_CLICKED(320),
+        @UiEvent(doc = "Notification action was clicked.")
+        NOTIFICATION_ACTION_CLICKED(321),
+        @UiEvent(doc = "Notification detail was expanded due to non-user action.")
+        NOTIFICATION_DETAIL_OPEN_SYSTEM(327),
+        @UiEvent(doc = "Notification detail was collapsed due to non-user action.")
+        NOTIFICATION_DETAIL_CLOSE_SYSTEM(328),
+        @UiEvent(doc = "Notification detail was expanded due to user action.")
+        NOTIFICATION_DETAIL_OPEN_USER(329),
+        @UiEvent(doc = "Notification detail was collapsed due to user action.")
+        NOTIFICATION_DETAIL_CLOSE_USER(330),
+        @UiEvent(doc = "Notification direct reply action was used.")
+        NOTIFICATION_DIRECT_REPLIED(331),
+        @UiEvent(doc = "Notification smart reply action was used.")
+        NOTIFICATION_SMART_REPLIED(332),
+        @UiEvent(doc = "Notification smart reply action was visible.")
+        NOTIFICATION_SMART_REPLY_VISIBLE(333),
+        ;
 
         private final int mId;
         NotificationEvent(int id) {
@@ -217,7 +255,29 @@
         public static NotificationEvent fromVisibility(boolean visible) {
             return visible ? NOTIFICATION_OPEN : NOTIFICATION_CLOSE;
         }
+        public static NotificationEvent fromExpanded(boolean expanded, boolean userAction) {
+            if (userAction) {
+                return expanded ? NOTIFICATION_DETAIL_OPEN_USER : NOTIFICATION_DETAIL_CLOSE_USER;
+            }
+            return expanded ? NOTIFICATION_DETAIL_OPEN_SYSTEM : NOTIFICATION_DETAIL_CLOSE_SYSTEM;
+        }
     }
+
+    enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Notification panel became visible.")
+        NOTIFICATION_PANEL_OPEN(325),
+        @UiEvent(doc = "Notification panel stopped being visible.")
+        NOTIFICATION_PANEL_CLOSE(326);
+
+        private final int mId;
+        NotificationPanelEvent(int id) {
+            mId = id;
+        }
+        @Override public int getId() {
+            return mId;
+        }
+    }
+
     /**
      * A helper for extracting logging information from one or two NotificationRecords.
      */
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index 9fcac25..494ff31 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -65,20 +65,16 @@
     }
 
     @Override
-    public void logNotificationCancelled(NotificationRecord r, int reason, int dismissalSurface) {
-        log(NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface), r);
-    }
-
-    @Override
-    public void logNotificationVisibility(NotificationRecord r, boolean visible) {
-        log(NotificationEvent.fromVisibility(visible), r);
-    }
-
-    void log(UiEventLogger.UiEventEnum event, NotificationRecord r) {
+    public void log(UiEventLogger.UiEventEnum event, NotificationRecord r) {
         if (r == null) {
             return;
         }
         mUiEventLogger.logWithInstanceId(event, r.getUid(), r.getSbn().getPackageName(),
                 r.getSbn().getInstanceId());
     }
+
+    @Override
+    public void log(UiEventLogger.UiEventEnum event) {
+        mUiEventLogger.log(event);
+    }
 }
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 6c2d77c..8349632 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -66,7 +66,7 @@
     @RequiresPermission(android.Manifest.permission.DUMP)
     public void startBugreport(int callingUidUnused, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
-            int bugreportMode, IDumpstateListener listener) {
+            int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
         Objects.requireNonNull(callingPackage);
         Objects.requireNonNull(bugreportFd);
@@ -88,7 +88,7 @@
         }
         synchronized (mLock) {
             startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
-                    bugreportMode, listener);
+                    bugreportMode, listener, isScreenshotRequested);
         }
     }
 
@@ -145,7 +145,7 @@
     @GuardedBy("mLock")
     private void startBugreportLocked(int callingUid, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
-            int bugreportMode, IDumpstateListener listener) {
+            int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
         if (isDumpstateBinderServiceRunningLocked()) {
             Slog.w(TAG, "'dumpstate' is already running. Cannot start a new bugreport"
                     + " while another one is currently in progress.");
@@ -165,7 +165,7 @@
         IDumpstateListener myListener = new DumpstateListener(listener, ds);
         try {
             ds.startBugreport(callingUid, callingPackage,
-                    bugreportFd, screenshotFd, bugreportMode, myListener);
+                    bugreportFd, screenshotFd, bugreportMode, myListener, isScreenshotRequested);
         } catch (RemoteException e) {
             // bugreportd service is already started now. We need to kill it to manage the
             // lifecycle correctly. If we don't subsequent callers will get
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 483f83e..28d7c13 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.content.pm.DataLoaderType.INCREMENTAL;
 import static android.content.pm.DataLoaderType.STREAMING;
 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
@@ -166,6 +167,8 @@
     private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
     private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
             "whitelisted-restricted-permission";
+    private static final String TAG_AUTO_REVOKE_PERMISSIONS_MODE =
+            "auto-revoke-permissions-mode";
     private static final String ATTR_SESSION_ID = "sessionId";
     private static final String ATTR_USER_ID = "userId";
     private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
@@ -311,8 +314,41 @@
     @GuardedBy("mLock")
     private int mParentSessionId;
 
+    static class FileEntry {
+        private final int mIndex;
+        private final InstallationFile mFile;
+
+        FileEntry(int index, InstallationFile file) {
+            this.mIndex = index;
+            this.mFile = file;
+        }
+
+        int getIndex() {
+            return this.mIndex;
+        }
+
+        InstallationFile getFile() {
+            return this.mFile;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof FileEntry)) {
+                return false;
+            }
+            final FileEntry rhs = (FileEntry) obj;
+            return (mFile.getLocation() == rhs.mFile.getLocation()) && TextUtils.equals(
+                    mFile.getName(), rhs.mFile.getName());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mFile.getLocation(), mFile.getName());
+        }
+    }
+
     @GuardedBy("mLock")
-    private ArrayList<InstallationFile> mFiles = new ArrayList<>();
+    private ArraySet<FileEntry> mFiles = new ArraySet<>();
 
     @GuardedBy("mLock")
     private boolean mStagedSessionApplied;
@@ -516,8 +552,12 @@
         this.mParentSessionId = parentSessionId;
 
         if (files != null) {
-            for (InstallationFile file : files) {
-                mFiles.add(file);
+            for (int i = 0, size = files.length; i < size; ++i) {
+                InstallationFile file = files[i];
+                if (!mFiles.add(new FileEntry(i, file))) {
+                    throw new IllegalArgumentException(
+                            "Trying to add a duplicate installation file");
+                }
             }
         }
 
@@ -623,6 +663,7 @@
             }
             info.grantedRuntimePermissions = params.grantedRuntimePermissions;
             info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
+            info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
             info.installFlags = params.installFlags;
             info.isMultiPackage = params.isMultiPackage;
             info.isStaged = params.isStaged;
@@ -750,9 +791,19 @@
             return result;
         }
 
-        String[] result = new String[mFiles.size()];
-        for (int i = 0, size = mFiles.size(); i < size; ++i) {
-            result[i] = mFiles.get(i).getName();
+        InstallationFile[] files = getInstallationFilesLocked();
+        String[] result = new String[files.length];
+        for (int i = 0, size = files.length; i < size; ++i) {
+            result[i] = files[i].getName();
+        }
+        return result;
+    }
+
+    @GuardedBy("mLock")
+    private InstallationFile[] getInstallationFilesLocked() {
+        final InstallationFile[] result = new InstallationFile[mFiles.size()];
+        for (FileEntry fileEntry : mFiles) {
+            result[fileEntry.getIndex()] = fileEntry.getFile();
         }
         return result;
     }
@@ -2444,7 +2495,10 @@
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotSealedLocked("addFile");
 
-            mFiles.add(new InstallationFile(location, name, lengthBytes, metadata, signature));
+            if (!mFiles.add(new FileEntry(mFiles.size(),
+                    new InstallationFile(location, name, lengthBytes, metadata, signature)))) {
+                throw new IllegalArgumentException("File already added: " + name);
+            }
         }
     }
 
@@ -2462,7 +2516,10 @@
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotSealedLocked("removeFile");
 
-            mFiles.add(new InstallationFile(location, getRemoveMarkerName(name), -1, null, null));
+            if (!mFiles.add(new FileEntry(mFiles.size(),
+                    new InstallationFile(location, getRemoveMarkerName(name), -1, null, null)))) {
+                throw new IllegalArgumentException("File already removed: " + name);
+            }
         }
     }
 
@@ -2482,7 +2539,8 @@
         final List<InstallationFileParcel> addedFiles = new ArrayList<>();
         final List<String> removedFiles = new ArrayList<>();
 
-        for (InstallationFile file : mFiles) {
+        final InstallationFile[] files = getInstallationFilesLocked();
+        for (InstallationFile file : files) {
             if (sAddedFilter.accept(new File(this.stageDir, file.getName()))) {
                 addedFiles.add(file.getData());
                 continue;
@@ -2889,6 +2947,13 @@
         }
     }
 
+    private static void writeAutoRevokePermissionsMode(@NonNull XmlSerializer out, int mode)
+            throws IOException {
+        out.startTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
+        writeIntAttribute(out, ATTR_MODE, mode);
+        out.endTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
+    }
+
 
     private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
         return new File(sessionsDir, "app_icon." + sessionId + ".png");
@@ -2969,6 +3034,7 @@
             writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
             writeWhitelistedRestrictedPermissionsLocked(out,
                     params.whitelistedRestrictedPermissions);
+            writeAutoRevokePermissionsMode(out, params.autoRevokePermissionsMode);
 
             // Persist app icon if changed since last written
             File appIconFile = buildAppIconFile(sessionId, sessionsDir);
@@ -2995,7 +3061,9 @@
                 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
                 out.endTag(null, TAG_CHILD_SESSION);
             }
-            for (InstallationFile file : mFiles) {
+
+            final InstallationFile[] files = getInstallationFilesLocked();
+            for (InstallationFile file : getInstallationFilesLocked()) {
                 out.startTag(null, TAG_SESSION_FILE);
                 writeIntAttribute(out, ATTR_LOCATION, file.getLocation());
                 writeStringAttribute(out, ATTR_NAME, file.getName());
@@ -3112,6 +3180,7 @@
         // depth.
         List<String> grantedRuntimePermissions = new ArrayList<>();
         List<String> whitelistedRestrictedPermissions = new ArrayList<>();
+        int autoRevokePermissionsMode = MODE_DEFAULT;
         List<Integer> childSessionIds = new ArrayList<>();
         List<InstallationFile> files = new ArrayList<>();
         int outerDepth = in.getDepth();
@@ -3128,6 +3197,9 @@
                 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
 
             }
+            if (TAG_AUTO_REVOKE_PERMISSIONS_MODE.equals(in.getName())) {
+                autoRevokePermissionsMode = readIntAttribute(in, ATTR_MODE);
+            }
             if (TAG_CHILD_SESSION.equals(in.getName())) {
                 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
             }
@@ -3150,6 +3222,8 @@
             params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
         }
 
+        params.autoRevokePermissionsMode = autoRevokePermissionsMode;
+
         int[] childSessionIdsArray;
         if (childSessionIds.size() > 0) {
             childSessionIdsArray = new int[childSessionIds.size()];
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 799ce65..24ebd32 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,6 +24,9 @@
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_DEFAULT;
 import static android.content.Intent.CATEGORY_HOME;
@@ -1654,12 +1657,13 @@
                                     && parentRes.pkg != null)
                                 ? parentRes.pkg.getRequestedPermissions()
                                 : args.whitelistedRestrictedPermissions;
+                        int autoRevokePermissionsMode = args.autoRevokePermissionsMode;
 
                         // Handle the parent package
                         handlePackagePostInstall(parentRes, grantPermissions,
                                 killApp, virtualPreload, grantedPermissions,
-                                whitelistedRestrictedPermissions, didRestore,
-                                args.installSource.installerPackageName, args.observer,
+                                whitelistedRestrictedPermissions, autoRevokePermissionsMode,
+                                didRestore, args.installSource.installerPackageName, args.observer,
                                 args.mDataLoaderType);
 
                         // Handle the child packages
@@ -1669,7 +1673,8 @@
                             PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
                             handlePackagePostInstall(childRes, grantPermissions,
                                     killApp, virtualPreload, grantedPermissions,
-                                    whitelistedRestrictedPermissions, false /*didRestore*/,
+                                    whitelistedRestrictedPermissions, autoRevokePermissionsMode,
+                                    false /*didRestore*/,
                                     args.installSource.installerPackageName, args.observer,
                                     args.mDataLoaderType);
                         }
@@ -1998,6 +2003,7 @@
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
             boolean killApp, boolean virtualPreload,
             String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+            int autoRevokePermissionsMode,
             boolean launchedForRestore, String installerPackage,
             IPackageInstallObserver2 installObserver, int dataLoaderType) {
         final boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
@@ -2018,6 +2024,11 @@
                         Process.myUid(), FLAG_PERMISSION_WHITELIST_INSTALLER);
             }
 
+            if (autoRevokePermissionsMode == MODE_ALLOWED || autoRevokePermissionsMode == MODE_IGNORED) {
+                mPermissionManager.setAutoRevokeWhitelisted(res.pkg.getPackageName(),
+                        autoRevokePermissionsMode == MODE_IGNORED, UserHandle.myUserId());
+            }
+
             // Now that we successfully installed the package, grant runtime
             // permissions if requested before broadcasting the install. Also
             // for legacy apps in permission review mode we clear the permission
@@ -11514,8 +11525,8 @@
                             "Static shared libs cannot declare permission groups");
                 }
 
-                // Static shared libs cannot declare features
-                if (!pkg.getFeatures().isEmpty()) {
+                // Static shared libs cannot declare attributions
+                if (!pkg.getAttributions().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare features");
                 }
@@ -14295,6 +14306,7 @@
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
         final List<String> whitelistedRestrictedPermissions;
+        final int autoRevokePermissionsMode;
         final VerificationInfo verificationInfo;
         final PackageParser.SigningDetails signingDetails;
         final int installReason;
@@ -14309,6 +14321,7 @@
                 int installFlags, InstallSource installSource, String volumeUuid,
                 VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
                 String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+                int autoRevokePermissionsMode,
                 SigningDetails signingDetails, int installReason,
                 long requiredInstalledVersionCode, int dataLoaderType) {
             super(user);
@@ -14322,6 +14335,7 @@
             this.packageAbiOverride = packageAbiOverride;
             this.grantedRuntimePermissions = grantedPermissions;
             this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
+            this.autoRevokePermissionsMode = autoRevokePermissionsMode;
             this.signingDetails = signingDetails;
             this.installReason = installReason;
             this.requiredInstalledVersionCode = requiredInstalledVersionCode;
@@ -14358,6 +14372,7 @@
             packageAbiOverride = sessionParams.abiOverride;
             grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
             whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
+            autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
             signingDetails = activeInstallSession.getSigningDetails();
             requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
             forceQueryableOverride = sessionParams.forceQueryableOverride;
@@ -14726,9 +14741,8 @@
             verificationState.setRequiredVerifierUid(requiredUid);
             final int installerUid =
                     verificationInfo == null ? -1 : verificationInfo.installerUid;
-            if (!origin.existing && requiredUid != -1
-                    && isVerificationEnabled(
-                            pkgLite, verifierUser.getIdentifier(), installFlags, installerUid)) {
+            if (!origin.existing && isVerificationEnabled(pkgLite, verifierUser.getIdentifier(),
+                      installFlags, installerUid)) {
                 final Intent verification = new Intent(
                         Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                 verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -14794,9 +14808,9 @@
                     }
                 }
 
-                final ComponentName requiredVerifierComponent = matchComponentForVerifier(
-                        mRequiredVerifierPackage, receivers);
                 if (mRequiredVerifierPackage != null) {
+                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
+                            mRequiredVerifierPackage, receivers);
                     /*
                      * Send the intent to the required verification agent,
                      * but only start the verification timeout after the
@@ -14954,6 +14968,7 @@
         final String abiOverride;
         final String[] installGrantPermissions;
         final List<String> whitelistedRestrictedPermissions;
+        final int autoRevokePermissionsMode;
         /** If non-null, drop an async trace when the install completes */
         final String traceMethod;
         final int traceCookie;
@@ -14973,6 +14988,7 @@
                 UserHandle user, String[] instructionSets,
                 String abiOverride, String[] installGrantPermissions,
                 List<String> whitelistedRestrictedPermissions,
+                int autoRevokePermissionsMode,
                 String traceMethod, int traceCookie, SigningDetails signingDetails,
                 int installReason, boolean forceQueryableOverride,
                 MultiPackageInstallParams multiPackageInstallParams, int dataLoaderType) {
@@ -14987,6 +15003,7 @@
             this.abiOverride = abiOverride;
             this.installGrantPermissions = installGrantPermissions;
             this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
+            this.autoRevokePermissionsMode = autoRevokePermissionsMode;
             this.traceMethod = traceMethod;
             this.traceCookie = traceCookie;
             this.signingDetails = signingDetails;
@@ -15002,6 +15019,7 @@
                     params.installSource, params.volumeUuid,
                     params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
                     params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
+                    params.autoRevokePermissionsMode,
                     params.traceMethod, params.traceCookie, params.signingDetails,
                     params.installReason, params.forceQueryableOverride,
                     params.mParentInstallParams, params.mDataLoaderType);
@@ -15093,7 +15111,7 @@
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
             super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
-                    null, null, instructionSets, null, null, null, null, 0,
+                    null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
                     PackageParser.SigningDetails.UNKNOWN,
                     PackageManager.INSTALL_REASON_UNKNOWN, false, null /* parent */,
                     DataLoaderType.NONE);
@@ -22469,7 +22487,8 @@
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
                 installSource, volumeUuid, null /*verificationInfo*/, user,
                 packageAbiOverride, null /*grantedPermissions*/,
-                null /*whitelistedRestrictedPermissions*/, PackageParser.SigningDetails.UNKNOWN,
+                null /*whitelistedRestrictedPermissions*/, MODE_DEFAULT /* autoRevokePermissions */,
+                PackageParser.SigningDetails.UNKNOWN,
                 PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST,
                 DataLoaderType.NONE);
         params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
@@ -24173,6 +24192,12 @@
             }
             mAppsFilter.getFeatureConfig().enableLogging(pkg.appId, enable);
         }
+
+        @Override
+        public boolean isSystemPackage(@NonNull String packageName) {
+            return packageName.equals(
+                    PackageManagerService.this.ensureSystemPackageName(packageName));
+        }
     }
 
     @GuardedBy("mLock")
@@ -24361,6 +24386,24 @@
     }
 
     @Override
+    public boolean isAutoRevokeWhitelisted(String packageName) {
+        int mode = mInjector.getAppOpsManager().checkOpNoThrow(
+                AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+                Binder.getCallingUid(), packageName);
+        if (mode == MODE_ALLOWED) {
+            return false;
+        } else if (mode == MODE_IGNORED) {
+            return true;
+        } else {
+            synchronized (mLock) {
+                boolean manifestWhitelisted =
+                        mPackages.get(packageName).isAllowDontAutoRevokePermmissions();
+                return manifestWhitelisted;
+            }
+        }
+    }
+
+    @Override
     public int getInstallReason(String packageName, int userId) {
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index be17dd8..8a9f1b3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3017,9 +3017,11 @@
 
     private int doAddFiles(int sessionId, ArrayList<String> args, long sessionSizeBytes,
             boolean isApex) throws RemoteException {
-        PackageInstaller.Session session = new PackageInstaller.Session(
-                mInterface.getPackageInstaller().openSession(sessionId));
+        PackageInstaller.Session session = null;
         try {
+            session = new PackageInstaller.Session(
+                    mInterface.getPackageInstaller().openSession(sessionId));
+
             // 1. Single file from stdin.
             if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
                 final String name = "base." + (isApex ? "apex" : "apk");
@@ -3043,6 +3045,10 @@
                 }
             }
             return 0;
+        } catch (IllegalArgumentException e) {
+            getErrPrintWriter().println("Failed to add file(s), reason: " + e);
+            getOutPrintWriter().println("Failure [failed to add file(s)]");
+            return 1;
         } finally {
             IoUtils.closeQuietly(session);
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index df3c83a..1c2fcc1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1300,14 +1300,15 @@
 
     @Override
     public boolean hasBadge(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "hasBadge");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "hasBadge");
         final UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
         return userTypeDetails != null && userTypeDetails.hasBadge();
     }
 
     @Override
     public @StringRes int getUserBadgeLabelResId(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getUserBadgeLabelResId");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
+                "getUserBadgeLabelResId");
         final UserInfo userInfo = getUserInfoNoChecks(userId);
         final UserTypeDetails userTypeDetails = getUserTypeDetails(userInfo);
         if (userInfo == null || userTypeDetails == null || !userTypeDetails.hasBadge()) {
@@ -1320,7 +1321,8 @@
 
     @Override
     public @ColorRes int getUserBadgeColorResId(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getUserBadgeColorResId");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
+                "getUserBadgeColorResId");
         final UserInfo userInfo = getUserInfoNoChecks(userId);
         final UserTypeDetails userTypeDetails = getUserTypeDetails(userInfo);
         if (userInfo == null || userTypeDetails == null || !userTypeDetails.hasBadge()) {
@@ -1333,7 +1335,7 @@
 
     @Override
     public @DrawableRes int getUserIconBadgeResId(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getUserIconBadgeResId");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getUserIconBadgeResId");
         final UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
         if (userTypeDetails == null || !userTypeDetails.hasBadge()) {
             Slog.e(LOG_TAG, "Requested icon badge for non-badged user " + userId);
@@ -1344,7 +1346,7 @@
 
     @Override
     public @DrawableRes int getUserBadgeResId(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getUserBadgeResId");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getUserBadgeResId");
         final UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
         if (userTypeDetails == null || !userTypeDetails.hasBadge()) {
             Slog.e(LOG_TAG, "Requested badge for non-badged user " + userId);
@@ -1355,7 +1357,7 @@
 
     @Override
     public @DrawableRes int getUserBadgeNoBackgroundResId(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId,
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
                 "getUserBadgeNoBackgroundResId");
         final UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
         if (userTypeDetails == null || !userTypeDetails.hasBadge()) {
@@ -1367,7 +1369,7 @@
 
     @Override
     public boolean isProfile(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isProfile");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isProfile");
         synchronized (mUsersLock) {
             UserInfo userInfo = getUserInfoLU(userId);
             return userInfo != null && userInfo.isProfile();
@@ -1376,7 +1378,7 @@
 
     @Override
     public boolean isManagedProfile(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isManagedProfile");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isManagedProfile");
         synchronized (mUsersLock) {
             UserInfo userInfo = getUserInfoLU(userId);
             return userInfo != null && userInfo.isManagedProfile();
@@ -1385,19 +1387,20 @@
 
     @Override
     public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isUserUnlockingOrUnlocked");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
+                "isUserUnlockingOrUnlocked");
         return mLocalService.isUserUnlockingOrUnlocked(userId);
     }
 
     @Override
     public boolean isUserUnlocked(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isUserUnlocked");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isUserUnlocked");
         return mLocalService.isUserUnlocked(userId);
     }
 
     @Override
     public boolean isUserRunning(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isUserRunning");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isUserRunning");
         return mLocalService.isUserRunning(userId);
     }
 
@@ -1437,7 +1440,7 @@
         }
     }
 
-    private void checkManageOrInteractPermIfCallerInOtherProfileGroup(@UserIdInt int userId,
+    private void checkManageOrInteractPermissionIfCallerInOtherProfileGroup(@UserIdInt int userId,
             String name) {
         final int callingUserId = UserHandle.getCallingUserId();
         if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) ||
@@ -1466,11 +1469,7 @@
 
     @Override
     public boolean isPreCreated(@UserIdInt int userId) {
-        final int callingUserId = UserHandle.getCallingUserId();
-        if (callingUserId != userId && !hasManageUsersPermission()) {
-            throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId
-                    + " is pre-created");
-        }
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isPreCreated");
         synchronized (mUsersLock) {
             UserInfo userInfo = getUserInfoLU(userId);
             return userInfo != null && userInfo.preCreated;
@@ -1826,7 +1825,7 @@
     /** @return a specific user restriction that's in effect currently. */
     @Override
     public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "hasUserRestriction");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "hasUserRestriction");
         return mLocalService.hasUserRestriction(restrictionKey, userId);
     }
 
@@ -1951,7 +1950,7 @@
      */
     @Override
     public Bundle getUserRestrictions(@UserIdInt int userId) {
-        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getUserRestrictions");
+        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getUserRestrictions");
         return UserRestrictionsUtils.clone(getEffectiveUserRestrictions(userId));
     }
 
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index d3f668c..0e294f70 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -391,8 +391,9 @@
         ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
         for (String key : procs.keySet()) {
             ParsedProcess proc = procs.get(key);
-            retProcs.put(proc.getName(), new ProcessInfo(proc.getName(),
-                    new ArraySet<>(proc.getDeniedPermissions())));
+            retProcs.put(proc.getName(),
+                    new ProcessInfo(proc.getName(), new ArraySet<>(proc.getDeniedPermissions()),
+                            proc.getEnableGwpAsan()));
         }
         return retProcs;
     }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 7929579..46b08df 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -25,7 +25,7 @@
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.os.Bundle;
@@ -147,7 +147,7 @@
     List<ParsedPermissionGroup> getPermissionGroups();
 
     @NonNull
-    List<ParsedFeature> getFeatures();
+    List<ParsedAttribution> getAttributions();
 
     /**
      * Used to determine the default preferred handler of an {@link Intent}.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 85da559..46f121d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -19,6 +19,8 @@
 import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -53,6 +55,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.app.ApplicationPackageManager;
 import android.app.IActivityManager;
 import android.app.admin.DeviceAdminInfo;
@@ -217,6 +220,9 @@
     /** Default permission policy to provide proper behaviour out-of-the-box */
     private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
 
+    /** App ops manager */
+    private final AppOpsManager mAppOpsManager;
+
     /**
      * Built-in permissions. Read from system configuration files. Mapping is from
      * UID to permission name.
@@ -356,6 +362,7 @@
         mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
         mUserManagerInt = LocalServices.getService(UserManagerInternal.class);
         mSettings = new PermissionSettings(mLock);
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
         mHandlerThread = new ServiceThread(TAG,
                 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
@@ -1199,6 +1206,77 @@
     }
 
     @Override
+    public boolean setAutoRevokeWhitelisted(
+            @NonNull String packageName, boolean whitelisted, int userId) {
+        Objects.requireNonNull(packageName);
+
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final int callingUid = Binder.getCallingUid();
+
+        if (!checkAutoRevokeAccess(pkg, callingUid)) {
+            return false;
+        }
+
+        if (mAppOpsManager
+                .checkOpNoThrow(AppOpsManager.OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
+                        callingUid, packageName)
+                != MODE_ALLOWED) {
+            // Whitelist user set - don't override
+            return false;
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mAppOpsManager.setMode(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+                    callingUid, packageName,
+                    whitelisted ? MODE_IGNORED : MODE_ALLOWED);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return true;
+    }
+
+    private boolean checkAutoRevokeAccess(AndroidPackage pkg, int callingUid) {
+        if (pkg == null) {
+            return false;
+        }
+
+        final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+                Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS)
+                == PackageManager.PERMISSION_GRANTED;
+        final boolean isCallerInstallerOnRecord =
+                mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
+
+        if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+            throw new SecurityException("Caller must either hold "
+                    + Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS
+                    + " or be the installer on record");
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isAutoRevokeWhitelisted(@NonNull String packageName, int userId) {
+        Objects.requireNonNull(packageName);
+
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final int callingUid = Binder.getCallingUid();
+
+        if (!checkAutoRevokeAccess(pkg, callingUid)) {
+            return false;
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mAppOpsManager.checkOpNoThrow(
+                    AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, callingUid, packageName)
+                    == MODE_IGNORED;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public void grantRuntimePermission(String packageName, String permName, final int userId) {
         final int callingUid = Binder.getCallingUid();
         final boolean overridePolicy =
@@ -3093,6 +3171,36 @@
         }
     }
 
+    @Override
+    public List<String> getAutoRevokeExemptionRequestedPackages(int userId) {
+        mContext.enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                "Must hold " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
+
+        List<String> result = new ArrayList<>();
+        mPackageManagerInt.forEachInstalledPackage(pkg -> {
+            if (pkg.isDontAutoRevokePermmissions()) {
+                result.add(pkg.getPackageName());
+            }
+        }, userId);
+
+        return result;
+    }
+
+    @Override
+    public List<String> getAutoRevokeExemptionGrantedPackages(int userId) {
+        mContext.enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                "Must hold " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
+
+        List<String> result = new ArrayList<>();
+        mPackageManagerInt.forEachInstalledPackage(pkg -> {
+            if (pkg.isAllowDontAutoRevokePermmissions()) {
+                result.add(pkg.getPackageName());
+            }
+        }, userId);
+
+        return result;
+    }
+
     private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
         boolean allowed = false;
         final int NP = PackageParser.NEW_PERMISSIONS.length;
@@ -4347,6 +4455,12 @@
                     packageName, permissions, flags, userId);
         }
         @Override
+        public void setAutoRevokeWhitelisted(
+                @NonNull String packageName, boolean whitelisted, int userId) {
+            PermissionManagerService.this.setAutoRevokeWhitelisted(
+                    packageName, whitelisted, userId);
+        }
+        @Override
         public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
             PermissionManagerService.this
                     .updatePermissions(packageName, pkg, mDefaultPermissionCallback);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 32ef2ce..356d0ab 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -189,7 +189,9 @@
     /** Sets the whitelisted, restricted permissions for the given package. */
     public abstract void setWhitelistedRestrictedPermissions(
             @NonNull String packageName, @NonNull List<String> permissions,
-            @PackageManager.PermissionWhitelistFlags int flags, @NonNull int userId);
+            @PackageManager.PermissionWhitelistFlags int flags, int userId);
+    public abstract void setAutoRevokeWhitelisted(
+            @NonNull String packageName, boolean whitelisted, int userId);
 
     /**
      * Update permissions when a package changed.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index d589353..161f304 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -32,6 +32,7 @@
 import android.app.AppOpsManagerInternal;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -173,6 +174,65 @@
         } catch (RemoteException doesNotHappen) {
             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
         }
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        intentFilter.addDataScheme("package");
+
+
+        /* TODO ntmyren: enable receiver when test flakes are fixed
+        getContext().registerReceiverAsUser(new BroadcastReceiver() {
+            final List<Integer> mUserSetupUids = new ArrayList<>(200);
+            final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
+                    new HashMap<>();
+
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                boolean hasSetupRun = true;
+                try {
+                    hasSetupRun = Settings.Secure.getInt(getContext().getContentResolver(),
+                            Settings.Secure.USER_SETUP_COMPLETE) != 0;
+                } catch (Settings.SettingNotFoundException e) {
+                    // Ignore error, assume setup has run
+                }
+                int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                // If there is no valid package for the given UID, return immediately
+                if (packageManagerInternal.getPackage(uid) == null) {
+                    return;
+                }
+
+                if (hasSetupRun) {
+                    if (!mUserSetupUids.isEmpty()) {
+                        synchronized (mUserSetupUids) {
+                            for (int i = mUserSetupUids.size() - 1; i >= 0; i--) {
+                                updateUid(mUserSetupUids.get(i));
+                            }
+                            mUserSetupUids.clear();
+                        }
+                    }
+                    updateUid(uid);
+                } else {
+                    synchronized (mUserSetupUids) {
+                        if (!mUserSetupUids.contains(uid)) {
+                            mUserSetupUids.add(uid);
+                        }
+                    }
+                }
+            }
+
+            private void updateUid(int uid) {
+                UserHandle user = UserHandle.getUserHandleForUid(uid);
+                PermissionControllerManager manager = mPermControllerManagers.get(user);
+                if (manager == null) {
+                    manager = new PermissionControllerManager(
+                            getUserContext(getContext(), user), FgThread.getHandler());
+                    mPermControllerManagers.put(user, manager);
+                }
+                manager.updateUserSensitiveForApp(uid);
+            }
+        }, UserHandle.ALL, intentFilter, null, null);
+         */
     }
 
     /**
@@ -182,7 +242,6 @@
      * {@link AppOpsManager#sOpToSwitch share an op} to control the access.
      *
      * @param permission The permission
-     *
      * @return The op that controls the access of the permission
      */
     private static int getSwitchOp(@NonNull String permission) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1b5cc6a..1e12565 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2139,8 +2139,10 @@
         }
 
         // check if user has enabled this operation. SecurityException will be thrown if this app
-        // has not been allowed by the user
-        final int mode = mAppOpsManager.noteOpNoThrow(outAppOp[0], callingUid, packageName);
+        // has not been allowed by the user. The reason to use "noteOp" (instead of checkOp) is to
+        // make sure the usage is logged.
+        final int mode = mAppOpsManager.noteOpNoThrow(outAppOp[0], callingUid, packageName,
+                null /* featureId */, "check-add");
         switch (mode) {
             case AppOpsManager.MODE_ALLOWED:
             case AppOpsManager.MODE_IGNORED:
@@ -5202,7 +5204,7 @@
                     if (dock != null) {
                         int result = ActivityTaskManager.getService()
                                 .startActivityAsUser(null, mContext.getBasePackageName(),
-                                        mContext.getFeatureId(), dock,
+                                        mContext.getAttributionTag(), dock,
                                         dock.resolveTypeIfNeeded(mContext.getContentResolver()),
                                         null, null, 0,
                                         ActivityManager.START_FLAG_ONLY_IF_NEEDED,
@@ -5214,7 +5216,7 @@
                 }
                 int result = ActivityTaskManager.getService()
                         .startActivityAsUser(null, mContext.getBasePackageName(),
-                                mContext.getFeatureId(), mHomeIntent,
+                                mContext.getAttributionTag(), mHomeIntent,
                                 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
                                 null, null, 0,
                                 ActivityManager.START_FLAG_ONLY_IF_NEEDED,
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index beba106..8b6e9a4 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -16,11 +16,13 @@
 package com.android.server.power.batterysaver;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManagerInternal;
 import android.hardware.power.V1_0.PowerHint;
 import android.os.BatteryManager;
 import android.os.BatterySaverPolicyConfig;
@@ -35,6 +37,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -49,6 +52,7 @@
 
 import java.util.ArrayList;
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * Responsible for battery saver mode transition logic.
@@ -112,6 +116,14 @@
      */
     private final Plugin[] mPlugins;
 
+    /**
+     * Package name that will receive an explicit manifest broadcast for
+     * {@link PowerManager#ACTION_POWER_SAVE_MODE_CHANGED}. It's {@code null} if it hasn't been
+     * retrieved yet.
+     */
+    @Nullable
+    private Optional<String> mPowerSaveModeChangedListenerPackage;
+
     public static final int REASON_PERCENTAGE_AUTOMATIC_ON = 0;
     public static final int REASON_PERCENTAGE_AUTOMATIC_OFF = 1;
     public static final int REASON_MANUAL_ON = 2;
@@ -494,6 +506,14 @@
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
 
+            // Send the broadcast to a manifest-registered receiver that is specified in the config.
+            if (getPowerSaveModeChangedListenerPackage().isPresent()) {
+                intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
+                        .setPackage(getPowerSaveModeChangedListenerPackage().get())
+                        .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+            }
+
             // Send internal version that requires signature permission.
             intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -508,6 +528,20 @@
         }
     }
 
+    private Optional<String> getPowerSaveModeChangedListenerPackage() {
+        if (mPowerSaveModeChangedListenerPackage == null) {
+            String configPowerSaveModeChangedListenerPackage =
+                    mContext.getString(R.string.config_powerSaveModeChangedListenerPackage);
+            mPowerSaveModeChangedListenerPackage =
+                    LocalServices
+                            .getService(PackageManagerInternal.class)
+                            .isSystemPackage(configPowerSaveModeChangedListenerPackage)
+                            ? Optional.of(configPowerSaveModeChangedListenerPackage)
+                            : Optional.empty();
+        }
+        return mPowerSaveModeChangedListenerPackage;
+    }
+
     private void updateBatterySavingStats() {
         final PowerManager pm = getPowerManager();
         if (pm == null) {
diff --git a/services/core/java/com/android/server/security/TEST_MAPPING b/services/core/java/com/android/server/security/TEST_MAPPING
new file mode 100644
index 0000000..9a5e90e
--- /dev/null
+++ b/services/core/java/com/android/server/security/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit": [
+    {
+      "name": "ApkVerityTest",
+      "file_patterns": ["VerityUtils\\.java"]
+    }
+  ]
+}
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 856a40f..2b793c8 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -81,22 +81,18 @@
 
     /** Returns whether the file has fs-verity enabled. */
     public static boolean hasFsverity(@NonNull String filePath) {
-        // NB: only measure but not check the actual measurement here. As long as this succeeds,
-        // the file is on readable if the measurement can be verified against a trusted key, and
-        // this is good enough for installed apps.
-        int errno = measureFsverityNative(filePath);
-        if (errno != 0) {
-            if (errno != OsConstants.ENODATA) {
-                Slog.e(TAG, "Failed to measure fs-verity, errno " + errno + ": " + filePath);
-            }
+        int retval = statxForFsverityNative(filePath);
+        if (retval < 0) {
+            Slog.e(TAG, "Failed to check whether fs-verity is enabled, errno " + -retval + ": "
+                    + filePath);
             return false;
         }
-        return true;
+        return (retval == 1);
     }
 
     private static native int enableFsverityNative(@NonNull String filePath,
             @NonNull byte[] pkcs7Signature);
-    private static native int measureFsverityNative(@NonNull String filePath);
+    private static native int statxForFsverityNative(@NonNull String filePath);
 
     /**
      * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped.
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 98579af5..fd275d8 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -406,8 +406,8 @@
                     case FrameworkStatsLog.BATTERY_VOLTAGE:
                     case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
                         return pullHealthHal(atomTag, data);
-                    case FrameworkStatsLog.APP_FEATURES_OPS:
-                        return pullAppFeaturesOps(atomTag, data);
+                    case FrameworkStatsLog.ATTRIBUTED_APP_OPS:
+                        return pullAttributedAppOps(atomTag, data);
                     default:
                         throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                 }
@@ -562,7 +562,7 @@
         registerAppsOnExternalStorageInfo();
         registerFaceSettings();
         registerAppOps();
-        registerAppFeaturesOps();
+        registerAttributedAppOps();
         registerRuntimeAppOpAccessMessage();
         registerNotificationRemoteViews();
         registerDangerousPermissionState();
@@ -2888,6 +2888,44 @@
             HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                     TimeUnit.MILLISECONDS);
             processHistoricalOps(histOps, atomTag, pulledData);
+
+            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.getLoggingOpCode());
+                        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());
+                    }
+                }
+            }
         } catch (Throwable t) {
             // TODO: catch exceptions at a more granular level
             Slog.e(TAG, "Could not read appops", t);
@@ -2898,8 +2936,8 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    private void registerAppFeaturesOps() {
-        int tagId = FrameworkStatsLog.APP_FEATURES_OPS;
+    private void registerAttributedAppOps() {
+        int tagId = FrameworkStatsLog.ATTRIBUTED_APP_OPS;
         mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
@@ -2908,7 +2946,7 @@
         );
     }
 
-    int pullAppFeaturesOps(int atomTag, List<StatsEvent> pulledData) {
+    int pullAttributedAppOps(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         try {
             AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -2946,7 +2984,7 @@
         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);
+        return processHistoricalOps(histOps, FrameworkStatsLog.ATTRIBUTED_APP_OPS, null);
     }
 
     int processHistoricalOps(HistoricalOps histOps, int atomTag, List<StatsEvent> pulledData) {
@@ -2956,15 +2994,15 @@
             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);
+                if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
+                    for (int attributionIdx = 0;
+                            attributionIdx < packageOps.getAttributedOpsCount(); attributionIdx++) {
+                        final AppOpsManager.AttributedHistoricalOps attributedOps =
+                                packageOps.getAttributedOpsAt(attributionIdx);
+                        for (int opIdx = 0; opIdx < attributedOps.getOpCount(); opIdx++) {
+                            final AppOpsManager.HistoricalOp op = attributedOps.getOpAt(opIdx);
                             counter += processHistoricalOp(op, atomTag, pulledData, uid,
-                                    packageOps.getPackageName(), featureOps.getFeatureId());
+                                    packageOps.getPackageName(), attributedOps.getTag());
                         }
                     }
                 } else if (atomTag == FrameworkStatsLog.APP_OPS) {
@@ -2981,18 +3019,19 @@
 
     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) {
+            @Nullable String attributionTag) {
+        if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_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());
+                    return 32 + packageName.length() + (attributionTag == null ? 1
+                            : attributionTag.length());
                 }
             } else {
-                if (abs((op.getOpCode() + feature + packageName).hashCode() + RANDOM_SEED) % 100
-                        >= mAppOpsSamplingRate) {
+                if (abs((op.getOpCode() + attributionTag + packageName).hashCode() + RANDOM_SEED)
+                        % 100 >= mAppOpsSamplingRate) {
                     return 0;
                 }
             }
@@ -3002,14 +3041,10 @@
         e.setAtomId(atomTag);
         e.writeInt(uid);
         e.writeString(packageName);
-        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
-            e.writeString(feature);
+        if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
+            e.writeString(attributionTag);
         }
-        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
-            e.writeString(op.getOpName());
-        } else {
-            e.writeInt(op.getOpCode());
-        }
+        e.writeInt(op.getLoggingOpCode());
         e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
         e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
         e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
@@ -3032,7 +3067,7 @@
                 e.writeBoolean(false);
             }
         }
-        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+        if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
             e.writeInt(mAppOpsSamplingRate);
         }
         pulledData.add(e.build());
@@ -3055,10 +3090,10 @@
             e.writeInt(message.getUid());
             e.writeString(message.getPackageName());
             e.writeString(message.getOp());
-            if (message.getFeatureId() == null) {
+            if (message.getAttributionTag() == null) {
                 e.writeString("");
             } else {
-                e.writeString(message.getFeatureId());
+                e.writeString(message.getAttributionTag());
             }
             e.writeString(message.getMessage());
             e.writeInt(message.getSamplingStrategy());
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 84cd4cf..78ef68c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -664,12 +664,13 @@
 
     @Override
     public void showAuthenticationDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
-            int biometricModality, boolean requireConfirmation, int userId, String opPackageName) {
+            int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
+            long operationId) {
         enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.showAuthenticationDialog(bundle, receiver, biometricModality,
-                        requireConfirmation, userId, opPackageName);
+                        requireConfirmation, userId, opPackageName, operationId);
             } catch (RemoteException ex) {
             }
         }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 8164526..74a6383 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -41,6 +41,7 @@
 import android.util.SparseArray;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.SelectionEvent;
+import android.view.textclassifier.SystemTextClassifierMetadata;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationConstants;
 import android.view.textclassifier.TextClassificationContext;
@@ -179,12 +180,12 @@
             TextSelection.Request request, ITextClassifierCallback callback)
             throws RemoteException {
         Objects.requireNonNull(request);
+        Objects.requireNonNull(request.getSystemTextClassifierMetadata());
 
         handleRequest(
-                request.getUserId(),
-                request.getCallingPackageName(),
+                request.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ true,
-                request.getUseDefaultTextClassifier(),
                 service -> service.onSuggestSelection(sessionId, request, callback),
                 "onSuggestSelection",
                 callback);
@@ -196,12 +197,12 @@
             TextClassification.Request request, ITextClassifierCallback callback)
             throws RemoteException {
         Objects.requireNonNull(request);
+        Objects.requireNonNull(request.getSystemTextClassifierMetadata());
 
         handleRequest(
-                request.getUserId(),
-                request.getCallingPackageName(),
+                request.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ true,
-                request.getUseDefaultTextClassifier(),
                 service -> service.onClassifyText(sessionId, request, callback),
                 "onClassifyText",
                 callback);
@@ -213,12 +214,12 @@
             TextLinks.Request request, ITextClassifierCallback callback)
             throws RemoteException {
         Objects.requireNonNull(request);
+        Objects.requireNonNull(request.getSystemTextClassifierMetadata());
 
         handleRequest(
-                request.getUserId(),
-                request.getCallingPackageName(),
+                request.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ true,
-                request.getUseDefaultTextClassifier(),
                 service -> service.onGenerateLinks(sessionId, request, callback),
                 "onGenerateLinks",
                 callback);
@@ -229,12 +230,12 @@
             @Nullable TextClassificationSessionId sessionId, SelectionEvent event)
             throws RemoteException {
         Objects.requireNonNull(event);
+        Objects.requireNonNull(event.getSystemTextClassifierMetadata());
 
         handleRequest(
-                event.getUserId(),
-                /* callingPackageName= */ null,
+                event.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ false,
                 /* attemptToBind= */ false,
-                event.getUseDefaultTextClassifier(),
                 service -> service.onSelectionEvent(sessionId, event),
                 "onSelectionEvent",
                 NO_OP_CALLBACK);
@@ -246,18 +247,14 @@
             TextClassifierEvent event) throws RemoteException {
         Objects.requireNonNull(event);
 
-        final int userId = event.getEventContext() == null
-                ? UserHandle.getCallingUserId()
-                : event.getEventContext().getUserId();
-        final boolean useDefaultTextClassifier =
-                event.getEventContext() != null
-                        ? event.getEventContext().getUseDefaultTextClassifier()
-                        : true;
+        final TextClassificationContext eventContext = event.getEventContext();
+        final SystemTextClassifierMetadata systemTcMetadata =
+                eventContext != null ? eventContext.getSystemTextClassifierMetadata() : null;
+
         handleRequest(
-                userId,
-                /* callingPackageName= */ null,
+                systemTcMetadata,
+                /* verifyCallingPackage= */ false,
                 /* attemptToBind= */ false,
-                useDefaultTextClassifier,
                 service -> service.onTextClassifierEvent(sessionId, event),
                 "onTextClassifierEvent",
                 NO_OP_CALLBACK);
@@ -269,12 +266,12 @@
             TextLanguage.Request request,
             ITextClassifierCallback callback) throws RemoteException {
         Objects.requireNonNull(request);
+        Objects.requireNonNull(request.getSystemTextClassifierMetadata());
 
         handleRequest(
-                request.getUserId(),
-                request.getCallingPackageName(),
+                request.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ true,
-                request.getUseDefaultTextClassifier(),
                 service -> service.onDetectLanguage(sessionId, request, callback),
                 "onDetectLanguage",
                 callback);
@@ -286,12 +283,12 @@
             ConversationActions.Request request,
             ITextClassifierCallback callback) throws RemoteException {
         Objects.requireNonNull(request);
+        Objects.requireNonNull(request.getSystemTextClassifierMetadata());
 
         handleRequest(
-                request.getUserId(),
-                request.getCallingPackageName(),
+                request.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ true,
-                request.getUseDefaultTextClassifier(),
                 service -> service.onSuggestConversationActions(sessionId, request, callback),
                 "onSuggestConversationActions",
                 callback);
@@ -303,13 +300,12 @@
             throws RemoteException {
         Objects.requireNonNull(sessionId);
         Objects.requireNonNull(classificationContext);
+        Objects.requireNonNull(classificationContext.getSystemTextClassifierMetadata());
 
-        final int userId = classificationContext.getUserId();
         handleRequest(
-                userId,
-                classificationContext.getPackageName(),
+                classificationContext.getSystemTextClassifierMetadata(),
+                /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ false,
-                classificationContext.getUseDefaultTextClassifier(),
                 service -> {
                     service.onCreateTextClassificationSession(classificationContext, sessionId);
                     mSessionCache.put(sessionId, classificationContext);
@@ -333,11 +329,13 @@
                     textClassificationContext != null
                             ? textClassificationContext.useDefaultTextClassifier
                             : true;
+            final SystemTextClassifierMetadata sysTcMetadata = new SystemTextClassifierMetadata(
+                    "", userId, useDefaultTextClassifier);
+
             handleRequest(
-                    userId,
-                    /* callingPackageName= */ null,
+                    sysTcMetadata,
+                    /* verifyCallingPackage= */ false,
                     /* attemptToBind= */ false,
-                    useDefaultTextClassifier,
                     service -> {
                         service.onDestroyTextClassificationSession(sessionId);
                         mSessionCache.remove(sessionId);
@@ -412,10 +410,9 @@
     }
 
     private void handleRequest(
-            @UserIdInt int userId,
-            @Nullable String callingPackageName,
+            @Nullable SystemTextClassifierMetadata sysTcMetadata,
+            boolean verifyCallingPackage,
             boolean attemptToBind,
-            boolean useDefaultTextClassifier,
             @NonNull ThrowingConsumer<ITextClassifierService> textClassifierServiceConsumer,
             @NonNull String methodName,
             @NonNull ITextClassifierCallback callback) throws RemoteException {
@@ -423,8 +420,17 @@
         Objects.requireNonNull(methodName);
         Objects.requireNonNull(callback);
 
+        final int userId =
+                sysTcMetadata == null ? UserHandle.getCallingUserId() : sysTcMetadata.getUserId();
+        final String callingPackageName =
+                sysTcMetadata == null ? null : sysTcMetadata.getCallingPackageName();
+        final boolean useDefaultTextClassifier =
+                sysTcMetadata == null ? true : sysTcMetadata.useDefaultTextClassifier();
+
         try {
-            validateCallingPackage(callingPackageName);
+            if (verifyCallingPackage) {
+                validateCallingPackage(callingPackageName);
+            }
             validateUser(userId);
         } catch (Exception e) {
             throw new RemoteException("Invalid request: " + e.getMessage(), e,
@@ -636,8 +642,10 @@
         public final boolean useDefaultTextClassifier;
 
         StrippedTextClassificationContext(TextClassificationContext textClassificationContext) {
-            userId = textClassificationContext.getUserId();
-            useDefaultTextClassifier = textClassificationContext.getUseDefaultTextClassifier();
+            SystemTextClassifierMetadata sysTcMetadata =
+                    textClassificationContext.getSystemTextClassifierMetadata();
+            userId = sysTcMetadata.getUserId();
+            useDefaultTextClassifier = sysTcMetadata.useDefaultTextClassifier();
         }
     }
 
diff --git a/services/core/java/com/android/server/tv/UinputBridge.java b/services/core/java/com/android/server/tv/UinputBridge.java
index 752aa66..a2fe5fc 100644
--- a/services/core/java/com/android/server/tv/UinputBridge.java
+++ b/services/core/java/com/android/server/tv/UinputBridge.java
@@ -28,7 +28,7 @@
 public final class UinputBridge {
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private long mPtr;
-    private IBinder mToken = null;
+    private IBinder mToken;
 
     private static native long nativeOpen(String name, String uniqueId, int width, int height,
                                           int maxPointers);
@@ -39,6 +39,25 @@
     private static native void nativeSendPointerUp(long ptr, int pointerId);
     private static native void nativeSendPointerSync(long ptr);
 
+    /** Opens a gamepad - will support gamepad key and axis sending */
+    private static native long nativeGamepadOpen(String name, String uniqueId);
+
+    /** Marks the specified key up/down for a gamepad */
+    private static native void nativeSendGamepadKey(long ptr, int keyIndex, boolean down);
+
+    /**
+     * Gamepads pre-define the following axes:
+     *   - Left joystick X, axis == ABS_X == 0, range [0, 254]
+     *   - Left joystick Y, axis == ABS_Y == 1, range [0, 254]
+     *   - Right joystick X, axis == ABS_RX == 3, range [0, 254]
+     *   - Right joystick Y, axis == ABS_RY == 4, range [0, 254]
+     *   - Left trigger, axis == ABS_Z == 2, range [0, 254]
+     *   - Right trigger, axis == ABS_RZ == 5, range [0, 254]
+     *   - DPad X, axis == ABS_HAT0X == 0x10, range [-1, 1]
+     *   - DPad Y, axis == ABS_HAT0Y == 0x11, range [-1, 1]
+     */
+    private static native void nativeSendGamepadAxisValue(long ptr, int axis, int value);
+
     public UinputBridge(IBinder token, String name, int width, int height, int maxPointers)
                         throws IOException {
         if (width < 1 || height < 1) {
@@ -58,12 +77,31 @@
         mCloseGuard.open("close");
     }
 
+    /** Constructor used by static factory methods */
+    private UinputBridge(IBinder token, long ptr) {
+        mPtr = ptr;
+        mToken = token;
+        mCloseGuard.open("close");
+    }
+
+    /** Opens a UinputBridge that supports gamepad buttons and axes. */
+    public static UinputBridge openGamepad(IBinder token, String name)
+            throws IOException {
+        if (token == null) {
+            throw new IllegalArgumentException("Token cannot be null");
+        }
+        long ptr = nativeGamepadOpen(name, token.toString());
+        if (ptr == 0) {
+            throw new IOException("Could not open uinput device " + name);
+        }
+
+        return new UinputBridge(token, ptr);
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
+            mCloseGuard.warnIfOpen();
             close(mToken);
         } finally {
             mToken = null;
@@ -119,7 +157,35 @@
         if (isTokenValid(token)) {
             nativeSendPointerSync(mPtr);
         }
+    }
 
+    /** Send a gamepad key
+     *  @param keyIndex - the index of the w3-spec key
+     *  @param down - is the key pressed ?
+     */
+    public void sendGamepadKey(IBinder token, int keyIndex, boolean down) {
+        if (isTokenValid(token)) {
+            nativeSendGamepadKey(mPtr, keyIndex, down);
+        }
+    }
+
+    /** Send a gamepad axis value.
+     *   - Left joystick X, axis == ABS_X == 0, range [0, 254]
+     *   - Left joystick Y, axis == ABS_Y == 1, range [0, 254]
+     *   - Right joystick X, axis == ABS_RX == 3, range [0, 254]
+     *   - Right joystick Y, axis == ABS_RY == 4, range [0, 254]
+     *   - Left trigger, axis == ABS_Z == 2, range [0, 254]
+     *   - Right trigger, axis == ABS_RZ == 5, range [0, 254]
+     *   - DPad X, axis == ABS_HAT0X == 0x10, range [-1, 1]
+     *   - DPad Y, axis == ABS_HAT0Y == 0x11, range [-1, 1]
+     *
+     * @param axis is the axis index
+     * @param value is the value to set for that axis
+     */
+    public void sendGamepadAxisValue(IBinder token, int axis, int value) {
+        if (isTokenValid(token)) {
+            nativeSendGamepadAxisValue(mPtr, axis, value);
+        }
     }
 
     public void clear(IBinder token) {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 04d551d..bd63b2d 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.tv.tunerresourcemanager;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -24,6 +25,8 @@
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ITunerResourceManager;
 import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
+import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
 import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
@@ -38,6 +41,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.SystemService;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -68,9 +73,31 @@
     private TvInputManager mManager;
     private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
 
+    // An internal resource request count to help generate resource handle.
+    private int mResourceRequestCount = 0;
+
     // Used to synchronize the access to the service.
     private final Object mLock = new Object();
 
+    /**
+     * Tuner resource type to help generate resource handle
+     */
+    @IntDef({
+        TUNER_RESOURCE_TYPE_FRONTEND,
+        TUNER_RESOURCE_TYPE_DEMUX,
+        TUNER_RESOURCE_TYPE_DESCRAMBLER,
+        TUNER_RESOURCE_TYPE_LNB,
+        TUNER_RESOURCE_TYPE_CAS_SESSION,
+     })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TunerResourceType {}
+
+    public static final int TUNER_RESOURCE_TYPE_FRONTEND = 0;
+    public static final int TUNER_RESOURCE_TYPE_DEMUX = 1;
+    public static final int TUNER_RESOURCE_TYPE_DESCRAMBLER = 2;
+    public static final int TUNER_RESOURCE_TYPE_LNB = 3;
+    public static final int TUNER_RESOURCE_TYPE_CAS_SESSION = 4;
+
     public TunerResourceManagerService(@Nullable Context context) {
         super(context);
     }
@@ -94,7 +121,7 @@
         public void registerClientProfile(@NonNull ResourceClientProfile profile,
                 @NonNull IResourcesReclaimListener listener, @NonNull int[] clientId)
                 throws RemoteException {
-            enforceAccessPermission();
+            enforceTrmAccessPermission("registerClientProfile");
             if (profile == null) {
                 throw new RemoteException("ResourceClientProfile can't be null");
             }
@@ -118,7 +145,7 @@
 
         @Override
         public void unregisterClientProfile(int clientId) throws RemoteException {
-            enforceAccessPermission();
+            enforceTrmAccessPermission("unregisterClientProfile");
             synchronized (mLock) {
                 if (!checkClientExists(clientId)) {
                     Slog.e(TAG, "Unregistering non exists client:" + clientId);
@@ -130,7 +157,7 @@
 
         @Override
         public boolean updateClientPriority(int clientId, int priority, int niceValue) {
-            enforceAccessPermission();
+            enforceTrmAccessPermission("updateClientPriority");
             synchronized (mLock) {
                 return updateClientPriorityInternal(clientId, priority, niceValue);
             }
@@ -138,7 +165,7 @@
 
         @Override
         public void setFrontendInfoList(@NonNull TunerFrontendInfo[] infos) throws RemoteException {
-            enforceAccessPermission();
+            enforceTrmAccessPermission("setFrontendInfoList");
             if (infos == null) {
                 throw new RemoteException("TunerFrontendInfo can't be null");
             }
@@ -149,6 +176,7 @@
 
         @Override
         public void updateCasInfo(int casSystemId, int maxSessionNum) {
+            enforceTrmAccessPermission("updateCasInfo");
             if (DEBUG) {
                 Slog.d(TAG,
                         "updateCasInfo(casSystemId=" + casSystemId
@@ -158,6 +186,7 @@
 
         @Override
         public void setLnbInfoList(int[] lnbIds) {
+            enforceTrmAccessPermission("setLnbInfoList");
             if (DEBUG) {
                 for (int i = 0; i < lnbIds.length; i++) {
                     Slog.d(TAG, "updateLnbInfo(lnbId=" + lnbIds[i] + ")");
@@ -167,14 +196,15 @@
 
         @Override
         public boolean requestFrontend(@NonNull TunerFrontendRequest request,
-                @NonNull int[] frontendId) throws RemoteException {
-            enforceAccessPermission();
-            if (frontendId == null) {
-                throw new RemoteException("frontendId can't be null");
+                @NonNull int[] frontendHandle) throws RemoteException {
+            enforceTunerAccessPermission("requestFrontend");
+            enforceTrmAccessPermission("requestFrontend");
+            if (frontendHandle == null) {
+                throw new RemoteException("frontendHandle can't be null");
             }
             synchronized (mLock) {
                 try {
-                    return requestFrontendInternal(request, frontendId);
+                    return requestFrontendInternal(request, frontendHandle);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -183,14 +213,43 @@
 
         @Override
         public void shareFrontend(int selfClientId, int targetClientId) {
+            enforceTunerAccessPermission("shareFrontend");
+            enforceTrmAccessPermission("shareFrontend");
             if (DEBUG) {
                 Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId);
             }
         }
 
         @Override
+        public boolean requestDemux(@NonNull TunerDemuxRequest request,
+                    @NonNull int[] demuxHandle)  throws RemoteException {
+            enforceTunerAccessPermission("requestDemux");
+            enforceTrmAccessPermission("requestDemux");
+            if (demuxHandle == null) {
+                throw new RemoteException("demuxHandle can't be null");
+            }
+            synchronized (mLock) {
+                return requestDemuxInternal(request, demuxHandle);
+            }
+        }
+
+        @Override
+        public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
+                    @NonNull int[] descrambleHandle) throws RemoteException {
+            enforceDescramblerAccessPermission("requestDescrambler");
+            enforceTrmAccessPermission("requestDescrambler");
+            if (descrambleHandle == null) {
+                throw new RemoteException("descrambleHandle can't be null");
+            }
+            synchronized (mLock) {
+                return requestDescramblerInternal(request, descrambleHandle);
+            }
+        }
+
+        @Override
         public boolean requestCasSession(
-                @NonNull CasSessionRequest request, @NonNull int[] sessionResourceId) {
+                @NonNull CasSessionRequest request, @NonNull int[] sessionResourceHandle) {
+            enforceTrmAccessPermission("requestCasSession");
             if (DEBUG) {
                 Slog.d(TAG, "requestCasSession(request=" + request + ")");
             }
@@ -199,7 +258,9 @@
         }
 
         @Override
-        public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbId) {
+        public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbHandle) {
+            enforceTunerAccessPermission("requestLnb");
+            enforceTrmAccessPermission("requestLnb");
             if (DEBUG) {
                 Slog.d(TAG, "requestLnb(request=" + request + ")");
             }
@@ -208,13 +269,34 @@
 
         @Override
         public void releaseFrontend(int frontendId) {
+            enforceTunerAccessPermission("releaseFrontend");
+            enforceTrmAccessPermission("releaseFrontend");
             if (DEBUG) {
                 Slog.d(TAG, "releaseFrontend(id=" + frontendId + ")");
             }
         }
 
         @Override
+        public void releaseDemux(int demuxHandle) {
+            enforceTunerAccessPermission("releaseDemux");
+            enforceTrmAccessPermission("releaseDemux");
+            if (DEBUG) {
+                Slog.d(TAG, "releaseDemux(demuxHandle=" + demuxHandle + ")");
+            }
+        }
+
+        @Override
+        public void releaseDescrambler(int descramblerHandle) {
+            enforceTunerAccessPermission("releaseDescrambler");
+            enforceTrmAccessPermission("releaseDescrambler");
+            if (DEBUG) {
+                Slog.d(TAG, "releaseDescrambler(descramblerHandle=" + descramblerHandle + ")");
+            }
+        }
+
+        @Override
         public void releaseCasSession(int sessionResourceId) {
+            enforceTrmAccessPermission("releaseCasSession");
             if (DEBUG) {
                 Slog.d(TAG, "releaseCasSession(sessionResourceId=" + sessionResourceId + ")");
             }
@@ -222,6 +304,8 @@
 
         @Override
         public void releaseLnb(int lnbId) {
+            enforceTunerAccessPermission("releaseLnb");
+            enforceTrmAccessPermission("releaseLnb");
             if (DEBUG) {
                 Slog.d(TAG, "releaseLnb(lnbId=" + lnbId + ")");
             }
@@ -230,6 +314,7 @@
         @Override
         public boolean isHigherPriority(
                 ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile) {
+            enforceTrmAccessPermission("isHigherPriority");
             if (DEBUG) {
                 Slog.d(TAG,
                         "isHigherPriority(challengerProfile=" + challengerProfile
@@ -337,13 +422,13 @@
     }
 
     @VisibleForTesting
-    protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendId)
+    protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendHandle)
             throws RemoteException {
         if (DEBUG) {
             Slog.d(TAG, "requestFrontend(request=" + request + ")");
         }
 
-        frontendId[0] = TunerResourceManager.INVALID_FRONTEND_ID;
+        frontendHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
         if (!checkClientExists(request.getClientId())) {
             Slog.e(TAG, "Request frontend from unregistered client:" + request.getClientId());
             return false;
@@ -379,17 +464,20 @@
 
         // Grant frontend when there is unused resource.
         if (grantingFrontendId > -1) {
-            frontendId[0] = grantingFrontendId;
-            updateFrontendClientMappingOnNewGrant(frontendId[0], request.getClientId());
+            frontendHandle[0] = generateResourceHandle(
+                    TUNER_RESOURCE_TYPE_FRONTEND, grantingFrontendId);
+            updateFrontendClientMappingOnNewGrant(grantingFrontendId, request.getClientId());
             return true;
         }
 
         // When all the resources are occupied, grant the lowest priority resource if the
         // request client has higher priority.
         if (inUseLowestPriorityFrId > -1 && (requestClient.getPriority() > currentLowestPriority)) {
-            frontendId[0] = inUseLowestPriorityFrId;
-            reclaimFrontendResource(getFrontendResource(frontendId[0]).getOwnerClientId());
-            updateFrontendClientMappingOnNewGrant(frontendId[0], request.getClientId());
+            frontendHandle[0] = generateResourceHandle(
+                    TUNER_RESOURCE_TYPE_FRONTEND, inUseLowestPriorityFrId);
+            reclaimFrontendResource(getFrontendResource(
+                    inUseLowestPriorityFrId).getOwnerClientId());
+            updateFrontendClientMappingOnNewGrant(inUseLowestPriorityFrId, request.getClientId());
             return true;
         }
 
@@ -397,6 +485,24 @@
     }
 
     @VisibleForTesting
+    boolean requestDemuxInternal(TunerDemuxRequest request, int[] demuxHandle) {
+        if (DEBUG) {
+            Slog.d(TAG, "requestDemux(request=" + request + ")");
+        }
+        demuxHandle[0] = generateResourceHandle(TUNER_RESOURCE_TYPE_DEMUX, 0);
+        return true;
+    }
+
+    @VisibleForTesting
+    boolean requestDescramblerInternal(TunerDescramblerRequest request, int[] descramblerHandle) {
+        if (DEBUG) {
+            Slog.d(TAG, "requestDescrambler(request=" + request + ")");
+        }
+        descramblerHandle[0] = generateResourceHandle(TUNER_RESOURCE_TYPE_DESCRAMBLER, 0);
+        return true;
+    }
+
+    @VisibleForTesting
     protected class ResourcesReclaimListenerRecord implements IBinder.DeathRecipient {
         private final IResourcesReclaimListener mListener;
         private final int mClientId;
@@ -558,8 +664,24 @@
         return mClientProfiles.keySet().contains(clientId);
     }
 
-    private void enforceAccessPermission() {
-        getContext().enforceCallingOrSelfPermission(
-                "android.permission.TUNER_RESOURCE_ACCESS", TAG);
+    private int generateResourceHandle(@TunerResourceType int resourceType, int resourceId) {
+        return (resourceType & 0x000000ff) << 24
+                | (resourceId << 16)
+                | (mResourceRequestCount++ & 0xffff);
+    }
+
+    private void enforceTrmAccessPermission(String apiName) {
+        getContext().enforceCallingPermission("android.permission.TUNER_RESOURCE_ACCESS",
+                TAG + ": " + "apiName");
+    }
+
+    private void enforceTunerAccessPermission(String apiName) {
+        getContext().enforceCallingPermission("android.Manifest.permission.ACCESS_TV_TUNER",
+                TAG + ": " + "apiName");
+    }
+
+    private void enforceDescramblerAccessPermission(String apiName) {
+        getContext().enforceCallingPermission("android.Manifest.permission.ACCESS_TV_DESCRAMBLER",
+                TAG + ": " + "apiName");
     }
 }
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index 761fbf8..88a60dd 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -50,7 +50,7 @@
         implements AlarmManager.OnAlarmListener, Handler.Callback, LocationListener {
 
     private static final String TAG = "TwilightService";
-    private static final String FEATURE_ID = "TwilightService";
+    private static final String ATTRIBUTION_TAG = "TwilightService";
     private static final boolean DEBUG = false;
 
     private static final int MSG_START_LISTENING = 1;
@@ -74,7 +74,7 @@
     protected TwilightState mLastTwilightState;
 
     public TwilightService(Context context) {
-        super(context.createFeatureContext(FEATURE_ID));
+        super(context.createAttributionContext(ATTRIBUTION_TAG));
         mHandler = new Handler(Looper.getMainLooper(), this);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b6ad241..c4545fa 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1351,11 +1351,16 @@
                 mLetterbox.attachInput(w);
             }
             getPosition(mTmpPoint);
-            // Get the bounds of the "space-to-fill". In multi-window mode, the task-level
-            // represents this. In fullscreen-mode, the stack does (since the orientation letterbox
-            // is also applied to the task).
-            Rect spaceToFill = (inMultiWindowMode() || getStack() == null)
-                    ? task.getDisplayedBounds() : getStack().getDisplayedBounds();
+            // Get the bounds of the "space-to-fill". The transformed bounds have the highest
+            // priority because the activity is launched in a rotated environment. In multi-window
+            // mode, the task-level represents this. In fullscreen-mode, the task container does
+            // (since the orientation letterbox is also applied to the task).
+            final Rect transformedBounds = getFixedRotationTransformDisplayBounds();
+            final Rect spaceToFill = transformedBounds != null
+                    ? transformedBounds
+                    : inMultiWindowMode()
+                            ? task.getDisplayedBounds()
+                            : getRootTask().getParent().getDisplayedBounds();
             mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
@@ -1589,6 +1594,11 @@
             info.taskAffinity = uid + ":" + info.taskAffinity;
         }
         taskAffinity = info.taskAffinity;
+        if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
+                && !info.windowLayout.windowLayoutAffinity.startsWith(uid)) {
+            info.windowLayout.windowLayoutAffinity =
+                    uid + ":" + info.windowLayout.windowLayoutAffinity;
+        }
         stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
         nonLocalizedLabel = aInfo.nonLocalizedLabel;
         labelRes = aInfo.labelRes;
@@ -6357,33 +6367,17 @@
         if (mCompatDisplayInsets != null) {
             resolveSizeCompatModeConfiguration(newParentConfiguration);
         } else {
-            // We ignore activities' requested orientation in multi-window modes. Task level may
-            // take them into consideration when calculating bounds.
             if (inMultiWindowMode()) {
+                // We ignore activities' requested orientation in multi-window modes. Task level may
+                // take them into consideration when calculating bounds.
                 resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
-            }
-            final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
-            final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
-            // Use tmp bounds to calculate aspect ratio so we can know whether the activity should
-            // use restricted size (resolvedBounds may be the requested override bounds).
-            mTmpBounds.setEmpty();
-            applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
-            // If the out bounds is not empty, it means the activity cannot fill parent's app
-            // bounds, then the relative configuration (e.g. screen size, layout) needs to be
-            // resolved according to the bounds.
-            if (!mTmpBounds.isEmpty()) {
-                final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
-                resolvedBounds.set(mTmpBounds);
-                // Exclude the horizontal decor area because the activity will be centered
-                // horizontally in parent's app bounds to balance the visual appearance.
-                resolvedBounds.left = parentAppBounds.left;
-                task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
-                        getFixedRotationTransformDisplayInfo());
-                final int offsetX = getHorizontalCenterOffset(
-                        parentAppBounds.width(), resolvedBounds.width());
-                if (offsetX > 0) {
-                    offsetBounds(resolvedConfig, offsetX - resolvedBounds.left, 0 /* offsetY */);
+                // If the activity has requested override bounds, the configuration needs to be
+                // computed accordingly.
+                if (!matchParentBounds()) {
+                    task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
                 }
+            } else {
+                resolveFullscreenConfiguration(newParentConfiguration);
             }
         }
 
@@ -6395,6 +6389,43 @@
     }
 
     /**
+     * Resolves the configuration of activity in fullscreen mode. If the bounds are restricted by
+     * aspect ratio, the position will be centered horizontally in parent's app bounds to balance
+     * the visual appearance. The policy of aspect ratio has higher priority than the requested
+     * override bounds.
+     */
+    private void resolveFullscreenConfiguration(Configuration newParentConfiguration) {
+        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+        final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
+        final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
+        final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+        // Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
+        // restricted size (resolved bounds may be the requested override bounds).
+        mTmpBounds.setEmpty();
+        applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
+        // If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
+        // then there is space to be centered.
+        final boolean needToBeCentered = !mTmpBounds.isEmpty();
+        if (needToBeCentered) {
+            resolvedBounds.set(mTmpBounds);
+            // Exclude the horizontal decor area.
+            resolvedBounds.left = parentAppBounds.left;
+        }
+        if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
+            // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
+            // restrict, the bounds should be the requested override bounds.
+            task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+                    getFixedRotationTransformDisplayInfo());
+        }
+        if (needToBeCentered) {
+            // Offset to center relative to parent's app bounds.
+            final int offsetX = getHorizontalCenterOffset(
+                    parentAppBounds.width(), resolvedBounds.width());
+            offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
+        }
+    }
+
+    /**
      * Resolves consistent screen configuration for orientation and rotation changes without
      * inheriting the parent bounds.
      */
@@ -6502,7 +6533,7 @@
         // Above coordinates are in "@" space, now place "*" and "#" to screen space.
         final int screenPosX = parentAppBounds.left + offsetX;
         final int screenPosY = parentBounds.top;
-        if (screenPosX > 0 || screenPosY > 0) {
+        if (screenPosX != 0 || screenPosY != 0) {
             if (mSizeCompatBounds != null) {
                 mSizeCompatBounds.offset(screenPosX, screenPosY);
             }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 9bad799..4ebb423 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -153,7 +153,6 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.ITaskOrganizer;
 import android.view.SurfaceControl;
 
 import com.android.internal.annotations.GuardedBy;
@@ -307,8 +306,6 @@
     // TODO(task-hierarchy): remove when tiles can be actual parents
     TaskTile mTile = null;
 
-    private int mLastTaskOrganizerWindowingMode = -1;
-
     private final Handler mHandler;
 
     private class ActivityStackHandler extends Handler {
@@ -635,8 +632,6 @@
 
         super.onConfigurationChanged(newParentConfig);
 
-        updateTaskOrganizerState();
-
         // Only need to update surface size here since the super method will handle updating
         // surface position.
         updateSurfaceSize(getPendingTransaction());
@@ -692,30 +687,6 @@
         }
     }
 
-    void updateTaskOrganizerState() {
-        if (!isRootTask()) {
-            return;
-        }
-
-        final int windowingMode = getWindowingMode();
-        if (windowingMode == mLastTaskOrganizerWindowingMode) {
-            // If our windowing mode hasn't actually changed, then just stick
-            // with our old organizer. This lets us implement the semantic
-            // where SysUI can continue to manage it's old tasks
-            // while CTS temporarily takes over the registration.
-            return;
-        }
-        /*
-         * Different windowing modes may be managed by different task organizers. If
-         * getTaskOrganizer returns null, we still call setTaskOrganizer to
-         * make sure we clear it.
-         */
-        final ITaskOrganizer org =
-            mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
-        setTaskOrganizer(org);
-        mLastTaskOrganizerWindowingMode = windowingMode;
-    }
-
     @Override
     public void setWindowingMode(int windowingMode) {
         // Calling Task#setWindowingMode() for leaf task since this is the a specialization of
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 98e3d07..94821ac 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6523,6 +6523,7 @@
             lastReparentedStack.postReparent();
         }
         releaseSelfIfNeeded();
+        mDisplayPolicy.release();
 
         if (!mAllSleepTokens.isEmpty()) {
             mRootWindowContainer.mSleepTokens.removeAll(mAllSleepTokens);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ba61667..ab96c61 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -179,6 +179,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.GestureNavigationSettingsObserver;
 import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.util.function.TriConsumer;
@@ -259,7 +260,9 @@
     @Px
     private int mBottomGestureAdditionalInset;
     @Px
-    private int mSideGestureInset;
+    private int mLeftGestureInset;
+    @Px
+    private int mRightGestureInset;
 
     StatusBarManagerInternal getStatusBarManagerInternal() {
         synchronized (mServiceAcquireLock) {
@@ -427,6 +430,8 @@
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
 
+    private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+
     private class PolicyHandler extends Handler {
 
         PolicyHandler(Looper looper) {
@@ -651,6 +656,16 @@
         mRefreshRatePolicy = new RefreshRatePolicy(mService,
                 mDisplayContent.getDisplayInfo(),
                 mService.mHighRefreshRateBlacklist);
+
+        mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
+                mContext, () -> {
+            synchronized (mLock) {
+                onConfigurationChanged();
+                mSystemGestures.onConfigurationChanged();
+                mDisplayContent.updateSystemGestureExclusion();
+            }
+        });
+        mHandler.post(mGestureNavigationSettingsObserver::register);
     }
 
     void systemReady() {
@@ -723,7 +738,7 @@
     }
 
     boolean hasSideGestures() {
-        return mHasNavigationBar && mSideGestureInset > 0;
+        return mHasNavigationBar && (mLeftGestureInset > 0 || mRightGestureInset > 0);
     }
 
     public boolean navigationBarCanMove() {
@@ -1076,11 +1091,12 @@
                             inOutFrame.left = 0;
                             inOutFrame.top = 0;
                             inOutFrame.bottom = displayFrames.mDisplayHeight;
-                            inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
+                            inOutFrame.right = displayFrames.mUnrestricted.left + mLeftGestureInset;
                         });
                 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
                         (displayFrames, windowState, inOutFrame) -> {
-                            inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
+                            inOutFrame.left = displayFrames.mUnrestricted.right
+                                    - mRightGestureInset;
                             inOutFrame.top = 0;
                             inOutFrame.bottom = displayFrames.mDisplayHeight;
                             inOutFrame.right = displayFrames.mDisplayWidth;
@@ -2819,7 +2835,8 @@
         }
 
         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
-        mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
+        mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
+        mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
         mNavigationBarAlwaysShowOnSideGesture =
                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
@@ -3953,6 +3970,10 @@
         return false;
     }
 
+    void release() {
+        mHandler.post(mGestureNavigationSettingsObserver::unregister);
+    }
+
     @VisibleForTesting
     static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
         if (navBarWindow == null || !navBarWindow.isVisibleLw()
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 01f9888..30912e5 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -36,6 +36,7 @@
 import android.util.SparseArray;
 import android.view.InsetsAnimationControlCallbacks;
 import android.view.InsetsAnimationControlImpl;
+import android.view.InsetsAnimationControlRunner;
 import android.view.InsetsController;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
@@ -44,6 +45,7 @@
 import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.ViewRootImpl;
 import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsAnimation.Bounds;
 import android.view.WindowInsetsAnimationControlListener;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -327,7 +329,7 @@
         InsetsPolicyAnimationControlCallbacks mControlCallbacks;
 
         InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
-            super(show);
+            super(show, true /* useSfVsync */);
             mFinishCallback = finishCallback;
             mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
         }
@@ -360,8 +362,6 @@
                         mFocusedWin.getDisplayContent().getBounds(), getState(),
                         mListener, typesReady, this, mListener.getDurationMs(),
                         InsetsController.INTERPOLATOR, true,
-                        show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
-                                : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                         show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
                 SurfaceAnimationThread.getHandler().post(
                         () -> mListener.onReady(mAnimationControl, typesReady));
@@ -377,7 +377,7 @@
             }
 
             @Override
-            public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
+            public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
                 // Nothing's needed here. Finish steps is handled in the listener
                 // onAnimationFinished callback.
             }
@@ -406,14 +406,21 @@
                     applyParams(t, surfaceParams, mTmpFloat9);
                 }
                 t.apply();
+                t.close();
+            }
+
+            // Since we don't push applySurfaceParams to a Handler-queue we don't need
+            // to push release in this case.
+            @Override
+            public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+                sc.release();
             }
 
             @Override
             public void startAnimation(InsetsAnimationControlImpl controller,
                     WindowInsetsAnimationControlListener listener, int types,
                     WindowInsetsAnimation animation,
-                    WindowInsetsAnimation.Bounds bounds,
-                    int layoutDuringAnimation) {
+                    Bounds bounds) {
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 660706e..9371c0e 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -16,7 +16,9 @@
 
 package com.android.server.wm;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManagerInternal;
 import android.graphics.Rect;
 import android.os.Environment;
@@ -87,9 +89,17 @@
      * launching activity of tasks) to {@link PersistableLaunchParams} that stores launch metadata
      * that are stable across reboots.
      */
-    private final SparseArray<ArrayMap<ComponentName, PersistableLaunchParams>> mMap =
+    private final SparseArray<ArrayMap<ComponentName, PersistableLaunchParams>> mLaunchParamsMap =
             new SparseArray<>();
 
+    /**
+     * A map from {@link android.content.pm.ActivityInfo.WindowLayout#windowLayoutAffinity} to
+     * activity's component name for reverse queries from window layout affinities to activities.
+     * Used to decide if we should use another activity's record with the same affinity.
+     */
+    private final ArrayMap<String, ArraySet<ComponentName>> mWindowLayoutAffinityMap =
+            new ArrayMap<>();
+
     LaunchParamsPersister(PersisterQueue persisterQueue, ActivityStackSupervisor supervisor) {
         this(persisterQueue, supervisor, Environment::getDataSystemCeDirectory);
     }
@@ -112,7 +122,7 @@
     }
 
     void onCleanupUser(int userId) {
-        mMap.remove(userId);
+        mLaunchParamsMap.remove(userId);
     }
 
     private void loadLaunchParams(int userId) {
@@ -128,7 +138,7 @@
         final File[] paramsFiles = launchParamsFolder.listFiles();
         final ArrayMap<ComponentName, PersistableLaunchParams> map =
                 new ArrayMap<>(paramsFiles.length);
-        mMap.put(userId, map);
+        mLaunchParamsMap.put(userId, map);
 
         for (File paramsFile : paramsFiles) {
             if (!paramsFile.isFile()) {
@@ -179,10 +189,12 @@
                         continue;
                     }
 
-                    params.restoreFromXml(parser);
+                    params.restore(paramsFile, parser);
                 }
 
                 map.put(name, params);
+                addComponentNameToLaunchParamAffinityMapIfNotNull(
+                        name, params.mWindowLayoutAffinity);
             } catch (Exception e) {
                 Slog.w(TAG, "Failed to restore launch params for " + name, e);
                 filesToDelete.add(paramsFile);
@@ -204,19 +216,17 @@
         final ComponentName name = task.realActivity;
         final int userId = task.mUserId;
         PersistableLaunchParams params;
-        ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
+        ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId);
         if (map == null) {
             map = new ArrayMap<>();
-            mMap.put(userId, map);
+            mLaunchParamsMap.put(userId, map);
         }
 
-        params = map.get(name);
-        if (params == null) {
-            params = new PersistableLaunchParams();
-            map.put(name, params);
-        }
+        params = map.computeIfAbsent(name, componentName -> new PersistableLaunchParams());
         final boolean changed = saveTaskToLaunchParam(task, display, params);
 
+        addComponentNameToLaunchParamAffinityMapIfNotNull(name, params.mWindowLayoutAffinity);
+
         if (changed) {
             mPersisterQueue.updateLastOrAddItem(
                     new LaunchParamsWriteQueueItem(userId, name, params),
@@ -243,19 +253,63 @@
             params.mBounds.setEmpty();
         }
 
+        String launchParamAffinity = task.mWindowLayoutAffinity;
+        changed |= Objects.equals(launchParamAffinity, params.mWindowLayoutAffinity);
+        params.mWindowLayoutAffinity = launchParamAffinity;
+
+        if (changed) {
+            params.mTimestamp = System.currentTimeMillis();
+        }
+
         return changed;
     }
 
+    private void addComponentNameToLaunchParamAffinityMapIfNotNull(
+            ComponentName name, String launchParamAffinity) {
+        if (launchParamAffinity == null) {
+            return;
+        }
+        mWindowLayoutAffinityMap.computeIfAbsent(launchParamAffinity, affinity -> new ArraySet<>())
+                .add(name);
+    }
+
     void getLaunchParams(Task task, ActivityRecord activity, LaunchParams outParams) {
         final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent;
         final int userId = task != null ? task.mUserId : activity.mUserId;
+        final String windowLayoutAffinity;
+        if (task != null) {
+            windowLayoutAffinity = task.mWindowLayoutAffinity;
+        } else {
+            ActivityInfo.WindowLayout layout = activity.info.windowLayout;
+            windowLayoutAffinity = layout == null ? null : layout.windowLayoutAffinity;
+        }
 
         outParams.reset();
-        Map<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
+        Map<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId);
         if (map == null) {
             return;
         }
-        final PersistableLaunchParams persistableParams = map.get(name);
+
+        // First use its own record as a reference.
+        PersistableLaunchParams persistableParams = map.get(name);
+        // Next we'll compare these params against all existing params with the same affinity and
+        // use the newest one.
+        if (windowLayoutAffinity != null
+                && mWindowLayoutAffinityMap.get(windowLayoutAffinity) != null) {
+            ArraySet<ComponentName> candidates = mWindowLayoutAffinityMap.get(windowLayoutAffinity);
+            for (int i = 0; i < candidates.size(); ++i) {
+                ComponentName candidate = candidates.valueAt(i);
+                final PersistableLaunchParams candidateParams = map.get(candidate);
+                if (candidateParams == null) {
+                    continue;
+                }
+
+                if (persistableParams == null
+                        || candidateParams.mTimestamp > persistableParams.mTimestamp) {
+                    persistableParams = candidateParams;
+                }
+            }
+        }
 
         if (persistableParams == null) {
             return;
@@ -272,10 +326,10 @@
 
     void removeRecordForPackage(String packageName) {
         final List<File> fileToDelete = new ArrayList<>();
-        for (int i = 0; i < mMap.size(); ++i) {
-            int userId = mMap.keyAt(i);
+        for (int i = 0; i < mLaunchParamsMap.size(); ++i) {
+            int userId = mLaunchParamsMap.keyAt(i);
             final File launchParamsFolder = getLaunchParamFolder(userId);
-            ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.valueAt(i);
+            ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.valueAt(i);
             for (int j = map.size() - 1; j >= 0; --j) {
                 final ComponentName name = map.keyAt(j);
                 if (name.getPackageName().equals(packageName)) {
@@ -409,6 +463,7 @@
         private static final String ATTR_WINDOWING_MODE = "windowing_mode";
         private static final String ATTR_DISPLAY_UNIQUE_ID = "display_unique_id";
         private static final String ATTR_BOUNDS = "bounds";
+        private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
 
         /** The bounds within the parent container. */
         final Rect mBounds = new Rect();
@@ -419,14 +474,29 @@
         /** The windowing mode to be in. */
         int mWindowingMode;
 
+        /**
+         * Last {@link android.content.pm.ActivityInfo.WindowLayout#windowLayoutAffinity} of the
+         * window.
+         */
+        @Nullable String mWindowLayoutAffinity;
+
+        /**
+         * Timestamp from {@link System#currentTimeMillis()} when this record is captured, or last
+         * modified time when the record is restored from storage.
+         */
+        long mTimestamp;
+
         void saveToXml(XmlSerializer serializer) throws IOException {
             serializer.attribute(null, ATTR_DISPLAY_UNIQUE_ID, mDisplayUniqueId);
             serializer.attribute(null, ATTR_WINDOWING_MODE,
                     Integer.toString(mWindowingMode));
             serializer.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
+            if (mWindowLayoutAffinity != null) {
+                serializer.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
+            }
         }
 
-        void restoreFromXml(XmlPullParser parser) {
+        void restore(File xmlFile, XmlPullParser parser) {
             for (int i = 0; i < parser.getAttributeCount(); ++i) {
                 final String attrValue = parser.getAttributeValue(i);
                 switch (parser.getAttributeName(i)) {
@@ -443,16 +513,28 @@
                         }
                         break;
                     }
+                    case ATTR_WINDOW_LAYOUT_AFFINITY:
+                        mWindowLayoutAffinity = attrValue;
+                        break;
                 }
             }
+
+            // The modified time could be a few seconds later than the timestamp when the record is
+            // captured, which is a good enough estimate to the capture time after a reboot or a
+            // user switch.
+            mTimestamp = xmlFile.lastModified();
         }
 
         @Override
         public String toString() {
             final StringBuilder builder = new StringBuilder("PersistableLaunchParams{");
-            builder.append("windowingMode=" + mWindowingMode);
+            builder.append(" windowingMode=" + mWindowingMode);
             builder.append(" displayUniqueId=" + mDisplayUniqueId);
             builder.append(" bounds=" + mBounds);
+            if (mWindowLayoutAffinity != null) {
+                builder.append(" launchParamsAffinity=" + mWindowLayoutAffinity);
+            }
+            builder.append(" timestamp=" + mTimestamp);
             builder.append(" }");
             return builder.toString();
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 15a49a7..ebf1bc9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2695,7 +2695,9 @@
                 return true;
             }
         } else {
-            if (r.intent.getComponent().equals(cls)) {
+            // Compare the target component instead of intent component so we don't miss if the
+            // activity uses alias.
+            if (r.mActivityComponent.equals(cls)) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index 36861aa..a696daf 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -103,7 +103,7 @@
      */
     void unfreeze(SurfaceControl.Transaction t) {
         if (mSnapshot != null) {
-            mSnapshot.destroy(t);
+            mSnapshot.cancelAnimation(t, false /* restarting */);
         }
         if (mLeash == null) {
             return;
@@ -212,7 +212,7 @@
          * @param t The transaction to use for all cancelling surface operations.
          * @param restarting Whether we are restarting the animation.
          */
-        private void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
+        void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
             final SurfaceControl leash = mSurfaceControl;
             final AnimationAdapter animation = mAnimation;
             final SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback =
@@ -229,7 +229,6 @@
                 }
             }
             if (!restarting) {
-                // TODO: do we need to destroy?
                 destroy(t);
             }
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 5ed903e..e78f2ee 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -199,6 +199,7 @@
     private static final String ATTR_MIN_WIDTH = "min_width";
     private static final String ATTR_MIN_HEIGHT = "min_height";
     private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
+    private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
 
     // Current version of the task record we persist. Used to check if we need to run any upgrade
     // code.
@@ -233,6 +234,8 @@
 
     String affinity;        // The affinity name for this task, or null; may change identity.
     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
+    String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving
+                                // launch params of this task.
     IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
     IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
     Intent intent;          // The original intent that started the task. Note that this value can
@@ -474,6 +477,7 @@
      * taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
      */
     ITaskOrganizer mTaskOrganizer;
+    private int mLastTaskOrganizerWindowingMode = -1;
 
     /**
      * Last Picture-in-Picture params applicable to the task. Updated when the app
@@ -1000,6 +1004,8 @@
                 origActivity = new ComponentName(info.packageName, info.name);
             }
         }
+        mWindowLayoutAffinity =
+                info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity;
 
         final int intentFlags = intent == null ? 0 : intent.getFlags();
         if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -1929,6 +1935,7 @@
         // TODO: Should also take care of Pip mode changes here.
 
         saveLaunchingStateIfNeeded();
+        updateTaskOrganizerState(false /* forceUpdate */);
     }
 
     /**
@@ -2120,14 +2127,26 @@
         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
     }
 
+    /**
+     * Forces the app bounds related configuration can be computed by
+     * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
+     * ActivityRecord.CompatDisplayInsets)}.
+     */
+    private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
+        final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
+        if (appBounds != null) {
+            appBounds.setEmpty();
+        }
+        inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+        inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+    }
+
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
         if (overrideDisplayInfo != null) {
             // Make sure the screen related configs can be computed by the provided display info.
-            inOutConfig.windowConfiguration.setAppBounds(null);
             inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
-            inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
-            inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+            invalidateAppBoundsConfig(inOutConfig);
         }
         computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
                 null /* compatInsets */);
@@ -2142,6 +2161,10 @@
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig,
             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+        if (compatInsets != null) {
+            // Make sure the app bounds can be computed by the compat insets.
+            invalidateAppBoundsConfig(inOutConfig);
+        }
         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
                 compatInsets);
     }
@@ -3363,6 +3386,9 @@
         } else {
             info.pictureInPictureParams = mPictureInPictureParams;
         }
+        info.topActivityInfo = mReuseActivitiesReport.top != null
+                ? mReuseActivitiesReport.top.info
+                : null;
     }
 
     /**
@@ -3408,6 +3434,9 @@
                 pw.println();
             }
         }
+        if (mWindowLayoutAffinity != null) {
+            pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity);
+        }
         if (voiceSession != null || voiceInteractor != null) {
             pw.print(prefix); pw.print("VOICE: session=0x");
             pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
@@ -3589,6 +3618,9 @@
         } else if (rootAffinity != null) {
             out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
         }
+        if (mWindowLayoutAffinity != null) {
+            out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
+        }
         out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
         out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
         out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
@@ -3746,6 +3778,7 @@
             String affinity = null;
             String rootAffinity = null;
             boolean hasRootAffinity = false;
+            String windowLayoutAffinity = null;
             boolean rootHasReset = false;
             boolean autoRemoveRecents = false;
             boolean askedCompatMode = false;
@@ -3798,6 +3831,9 @@
                         rootAffinity = attrValue;
                         hasRootAffinity = true;
                         break;
+                    case ATTR_WINDOW_LAYOUT_AFFINITY:
+                        windowLayoutAffinity = attrValue;
+                        break;
                     case ATTR_ROOTHASRESET:
                         rootHasReset = Boolean.parseBoolean(attrValue);
                         break;
@@ -3953,6 +3989,7 @@
                     realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*stack*/);
             task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
             task.setBounds(lastNonFullscreenBounds);
+            task.mWindowLayoutAffinity = windowLayoutAffinity;
 
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 task.addChild(activities.get(activityNdx));
@@ -4018,6 +4055,39 @@
     // Called on Binder death.
     void taskOrganizerDied() {
         mTaskOrganizer = null;
+        mLastTaskOrganizerWindowingMode = -1;
+    }
+
+    /**
+     * Called when the task state changes (ie. from windowing mode change) an the task organizer
+     * state should also be updated.
+     *
+     * @param forceUpdate Updates the task organizer to the one currently specified in the task
+     *                    org controller for the task's windowing mode, ignoring the cached
+     *                    windowing mode checks.
+     */
+    void updateTaskOrganizerState(boolean forceUpdate) {
+        if (!isRootTask()) {
+            return;
+        }
+
+        final int windowingMode = getWindowingMode();
+        if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) {
+            // If our windowing mode hasn't actually changed, then just stick
+            // with our old organizer. This lets us implement the semantic
+            // where SysUI can continue to manage it's old tasks
+            // while CTS temporarily takes over the registration.
+            return;
+        }
+        /*
+         * Different windowing modes may be managed by different task organizers. If
+         * getTaskOrganizer returns null, we still call setTaskOrganizer to
+         * make sure we clear it.
+         */
+        final ITaskOrganizer org =
+                mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
+        setTaskOrganizer(org);
+        mLastTaskOrganizerWindowingMode = windowingMode;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index cfb5706..9cbc9ee 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -105,7 +105,7 @@
 
 
         TaskOrganizerState(ITaskOrganizer organizer, int windowingMode,
-                TaskOrganizerState replacing) {
+                @Nullable TaskOrganizerState replacing) {
             mOrganizer = organizer;
             mDeathRecipient = new DeathRecipient(organizer, windowingMode);
             try {
@@ -203,10 +203,27 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
+                if (getTaskOrganizer(windowingMode) != null) {
+                    Slog.w(TAG, "Task organizer already exists for windowing mode: "
+                            + windowingMode);
+                }
+                final TaskOrganizerState previousState =
+                        mTaskOrganizersForWindowingMode.get(windowingMode);
                 final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode,
-                        mTaskOrganizersForWindowingMode.get(windowingMode));
+                        previousState);
                 mTaskOrganizersForWindowingMode.put(windowingMode, state);
                 mTaskOrganizerStates.put(organizer.asBinder(), state);
+
+                if (previousState == null) {
+                    // Only in the case where this is the root task organizer for the given
+                    // windowing mode, we add report all existing tasks in that mode to the new
+                    // task organizer.
+                    mService.mRootWindowContainer.forAllTasks((task) -> {
+                        if (task.getWindowingMode() == windowingMode) {
+                            task.updateTaskOrganizerState(true /* forceUpdate */);
+                        }
+                    });
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index a60db94..0b11dd2 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -96,8 +96,8 @@
         mAnimationFrameCallback = frameTimeNs -> {
             synchronized (mService.mGlobalLock) {
                 mAnimationFrameCallbackScheduled = false;
+                animate(frameTimeNs);
             }
-            animate(frameTimeNs);
         };
     }
 
@@ -115,110 +115,94 @@
         mInitialized = true;
     }
 
-    /**
-     * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
-     * an animation transaction, that might be blocking until the next sf-vsync, so we want to make
-     * sure other threads can make progress if this happens.
-     */
     private void animate(long frameTimeNs) {
-
-        synchronized (mService.mGlobalLock) {
-            if (!mInitialized) {
-                return;
-            }
-
-            // Schedule next frame already such that back-pressure happens continuously
-            scheduleAnimation();
+        if (!mInitialized) {
+            return;
         }
 
-        synchronized (mService.mGlobalLock) {
-            mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
-            mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
-            if (DEBUG_WINDOW_TRACE) {
-                Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
+        // Schedule next frame already such that back-pressure happens continuously.
+        scheduleAnimation();
+
+        mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
+        mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
+        }
+
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
+        mService.openSurfaceTransaction();
+        try {
+            final AccessibilityController accessibilityController =
+                    mService.mAccessibilityController;
+            final int numDisplays = mDisplayContentsAnimators.size();
+            for (int i = 0; i < numDisplays; i++) {
+                final int displayId = mDisplayContentsAnimators.keyAt(i);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+                // Update animations of all applications, including those associated with
+                // exiting/removed apps.
+                dc.updateWindowsForAnimator();
+                dc.prepareSurfaces();
             }
 
-            ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
-            mService.openSurfaceTransaction();
-            try {
-                final AccessibilityController accessibilityController =
-                        mService.mAccessibilityController;
-                final int numDisplays = mDisplayContentsAnimators.size();
-                for (int i = 0; i < numDisplays; i++) {
-                    final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
-                    // Update animations of all applications, including those
-                    // associated with exiting/removed apps
-                    dc.updateWindowsForAnimator();
-                    dc.prepareSurfaces();
+            for (int i = 0; i < numDisplays; i++) {
+                final int displayId = mDisplayContentsAnimators.keyAt(i);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+
+                dc.checkAppWindowsReadyToShow();
+                if (accessibilityController != null) {
+                    accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
+                            mTransaction);
                 }
-
-                for (int i = 0; i < numDisplays; i++) {
-                    final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
-
-                    dc.checkAppWindowsReadyToShow();
-                    if (accessibilityController != null) {
-                        accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
-                                mTransaction);
-                    }
-                }
-
-                cancelAnimation();
-
-                if (mService.mWatermark != null) {
-                    mService.mWatermark.drawIfNeeded();
-                }
-
-                SurfaceControl.mergeToGlobalTransaction(mTransaction);
-            } catch (RuntimeException e) {
-                Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
-            } finally {
-                mService.closeSurfaceTransaction("WindowAnimator");
-                ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
             }
 
-            boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
-            boolean doRequest = false;
-            if (mBulkUpdateParams != 0) {
-                doRequest = mService.mRoot.copyAnimToLayoutParams();
+            cancelAnimation();
+
+            if (mService.mWatermark != null) {
+                mService.mWatermark.drawIfNeeded();
             }
 
-            if (hasPendingLayoutChanges || doRequest) {
-                mService.mWindowPlacerLocked.requestTraversal();
-            }
+            SurfaceControl.mergeToGlobalTransaction(mTransaction);
+        } catch (RuntimeException e) {
+            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
+        } finally {
+            mService.closeSurfaceTransaction("WindowAnimator");
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
+        }
 
-            final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN);
-            if (rootAnimating && !mLastRootAnimating) {
+        final boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
+        final boolean doRequest = mBulkUpdateParams != 0 && mService.mRoot.copyAnimToLayoutParams();
+        if (hasPendingLayoutChanges || doRequest) {
+            mService.mWindowPlacerLocked.requestTraversal();
+        }
 
-                // Usually app transitions but quite a load onto the system already (with all the
-                // things happening in app), so pause task snapshot persisting to not increase the
-                // load.
-                mService.mTaskSnapshotController.setPersisterPaused(true);
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
-            }
-            if (!rootAnimating && mLastRootAnimating) {
-                mService.mWindowPlacerLocked.requestTraversal();
-                mService.mTaskSnapshotController.setPersisterPaused(false);
-                Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
-            }
+        final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN);
+        if (rootAnimating && !mLastRootAnimating) {
+            // Usually app transitions but quite a load onto the system already (with all the things
+            // happening in app), so pause task snapshot persisting to not increase the load.
+            mService.mTaskSnapshotController.setPersisterPaused(true);
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+        }
+        if (!rootAnimating && mLastRootAnimating) {
+            mService.mWindowPlacerLocked.requestTraversal();
+            mService.mTaskSnapshotController.setPersisterPaused(false);
+            Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+        }
 
-            mLastRootAnimating = rootAnimating;
+        mLastRootAnimating = rootAnimating;
 
-            if (mRemoveReplacedWindows) {
-                mService.mRoot.removeReplacedWindows();
-                mRemoveReplacedWindows = false;
-            }
+        if (mRemoveReplacedWindows) {
+            mService.mRoot.removeReplacedWindows();
+            mRemoveReplacedWindows = false;
+        }
 
-            mService.destroyPreservedSurfaceLocked();
+        mService.destroyPreservedSurfaceLocked();
 
-            executeAfterPrepareSurfacesRunnables();
+        executeAfterPrepareSurfacesRunnables();
 
-            if (DEBUG_WINDOW_TRACE) {
-                Slog.i(TAG, "!!! animate: exit"
-                        + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
-                        + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
-            }
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.i(TAG, "!!! animate: exit"
+                    + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
+                    + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e8897e1..9a92832 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -275,7 +275,7 @@
     RemoteToken mRemoteToken = null;
 
     BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine();
-    SurfaceControl.Transaction mBLASTSyncTransaction = new SurfaceControl.Transaction();
+    SurfaceControl.Transaction mBLASTSyncTransaction;
     boolean mUsingBLASTSyncTransaction = false;
     BLASTSyncEngine.TransactionReadyListener mWaitingListener;
     int mWaitingSyncId;
@@ -283,6 +283,7 @@
     WindowContainer(WindowManagerService wms) {
         mWmService = wms;
         mPendingTransaction = wms.mTransactionFactory.get();
+        mBLASTSyncTransaction = wms.mTransactionFactory.get();
         mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
         mSurfaceFreezer = new SurfaceFreezer(this, wms);
     }
@@ -2460,6 +2461,19 @@
         mWaitingSyncId = -1;
     }
 
+    /**
+     * Returns true if any of the children elected to participate in the Sync
+     */
+    boolean addChildrenToSyncSet(int localId) {
+        boolean willSync = false;
+
+        for (int i = 0; i < mChildren.size(); i++) {
+            final WindowContainer child = mChildren.get(i);
+            willSync |= mBLASTSyncEngine.addToSyncSet(localId, child);
+        }
+        return willSync;
+    }
+
     boolean prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener,
             int waitingId) {
         boolean willSync = false;
@@ -2468,16 +2482,12 @@
         }
         mUsingBLASTSyncTransaction = true;
 
-        int localId = mBLASTSyncEngine.startSyncSet(this);
-        for (int i = 0; i < mChildren.size(); i++) {
-            final WindowContainer child = mChildren.get(i);
-            willSync = mBLASTSyncEngine.addToSyncSet(localId, child) | willSync;
-        }
-
         // Make sure to set these before we call setReady in case the sync was a no-op
         mWaitingSyncId = waitingId;
         mWaitingListener = waitingListener;
 
+        int localId = mBLASTSyncEngine.startSyncSet(this);
+        willSync |= addChildrenToSyncSet(localId);
         mBLASTSyncEngine.setReady(localId);
 
         return willSync;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ecbbb03..1a77807 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1007,9 +1007,7 @@
     void openSurfaceTransaction() {
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
-            synchronized (mGlobalLock) {
-                SurfaceControl.openTransaction();
-            }
+            SurfaceControl.openTransaction();
         } finally {
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
@@ -1022,10 +1020,8 @@
     void closeSurfaceTransaction(String where) {
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
-            synchronized (mGlobalLock) {
-                SurfaceControl.closeTransaction();
-                mWindowTracing.logState(where);
-            }
+            SurfaceControl.closeTransaction();
+            mWindowTracing.logState(where);
         } finally {
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 32eb932..f356329 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1058,7 +1058,7 @@
     }
 
     private void registerActivityConfigurationListener(ActivityRecord activityRecord) {
-        if (activityRecord == null) {
+        if (activityRecord == null || activityRecord.containsListener(this)) {
             return;
         }
         // A process can only register to one activityRecord to listen to the override configuration
@@ -1093,7 +1093,7 @@
 
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord activityRecord = mActivities.get(i);
-            if (!activityRecord.finishing && !activityRecord.containsListener(this)) {
+            if (!activityRecord.finishing) {
                 // Eligible activity is found, update listener.
                 registerActivityConfigurationListener(activityRecord);
                 return;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c44be4d..45e3690 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -679,6 +679,15 @@
      */
     int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;
 
+    /**
+     * BLASTSyncEngine ID corresponding to a sync-set for all
+     * our children. We add our children to this set in Sync,
+     * but we save it and don't mark it as ready until finishDrawing
+     * this way we have a two way latch between all our children finishing
+     * and drawing ourselves.
+     */
+    private int mLocalSyncId = -1;
+
     static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */
 
     /**
@@ -2929,8 +2938,9 @@
         // and add the window only if the permission was granted. Therefore, if
         // the mode is MODE_DEFAULT we want the op to succeed as the window is
         // shown.
-        final int mode = mWmService.mAppOps.startOpNoThrow(mAppOp,
-                getOwningUid(), getOwningPackage(), true);
+        final int mode = mWmService.mAppOps.startOpNoThrow(mAppOp, getOwningUid(),
+                getOwningPackage(), true /* startIfModeDefault */, null /* featureId */,
+                "init-default-visibility");
         if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) {
             setAppOpVisibilityLw(false);
         }
@@ -2938,7 +2948,8 @@
 
     void resetAppOpsState() {
         if (mAppOp != OP_NONE && mAppOpVisibility) {
-            mWmService.mAppOps.finishOp(mAppOp, getOwningUid(), getOwningPackage());
+            mWmService.mAppOps.finishOp(mAppOp, getOwningUid(), getOwningPackage(),
+                    null /* featureId */);
         }
     }
 
@@ -2953,11 +2964,12 @@
             // as this would mean we will get another change callback and will reconcile.
             int mode = mWmService.mAppOps.checkOpNoThrow(mAppOp, uid, packageName);
             if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) {
-                mWmService.mAppOps.finishOp(mAppOp, uid, packageName);
+                mWmService.mAppOps.finishOp(mAppOp, uid, packageName, null /* featureId */);
                 setAppOpVisibilityLw(false);
             }
         } else {
-            final int mode = mWmService.mAppOps.startOpNoThrow(mAppOp, uid, packageName, true);
+            final int mode = mWmService.mAppOps.startOpNoThrow(mAppOp, uid, packageName,
+                    true /* startIfModeDefault */, null /* featureId */, "attempt-to-be-visible");
             if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
                 setAppOpVisibilityLw(true);
             }
@@ -5684,11 +5696,13 @@
     @Override
     boolean prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener,
             int waitingId) {
-        // TODO(b/148871522): Support child window
         mWaitingListener = waitingListener;
         mWaitingSyncId = waitingId;
         mUsingBLASTSyncTransaction = true;
 
+        mLocalSyncId = mBLASTSyncEngine.startSyncSet(this);
+        addChildrenToSyncSet(mLocalSyncId);
+
         mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
         mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
             BLAST_TIMEOUT_DURATION);
@@ -5702,11 +5716,21 @@
         }
 
         mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
-        if (postDrawTransaction == null) {
-            postDrawTransaction = new SurfaceControl.Transaction();
+        if (postDrawTransaction != null) {
+            mBLASTSyncTransaction.merge(postDrawTransaction);
         }
-        postDrawTransaction.merge(mBLASTSyncTransaction);
-        mWaitingListener.transactionReady(mWaitingSyncId, postDrawTransaction);
+
+        // If localSyncId is >0 then we are syncing with children and will
+        // invoke transaction ready from our own #transactionReady callback
+        // we just need to signal our side of the sync (setReady). But if we
+        // have no sync operation at this level transactionReady will never
+        // be invoked and we need to invoke it ourself.
+        if (mLocalSyncId >= 0) {
+            mBLASTSyncEngine.setReady(mLocalSyncId);
+        } else {
+            mWaitingListener.transactionReady(mWaitingSyncId, mBLASTSyncTransaction);
+        }
+
         mUsingBLASTSyncTransaction = false;
 
         mWaitingSyncId = 0;
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 6f9d012..29b2cd6 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -172,26 +172,25 @@
 
 BlockHeader readHeader(std::span<uint8_t>& data);
 
-static inline int32_t readBEInt32(borrowed_fd fd) {
+static inline int32_t readLEInt32(borrowed_fd fd) {
     int32_t result;
     ReadFully(fd, &result, sizeof(result));
-    result = int32_t(be32toh(result));
+    result = int32_t(le32toh(result));
     return result;
 }
 
 static inline std::vector<char> readBytes(borrowed_fd fd) {
-    int32_t size = readBEInt32(fd);
+    int32_t size = readLEInt32(fd);
     std::vector<char> result(size);
     ReadFully(fd, result.data(), size);
     return result;
 }
 
 static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
-    readBEInt32(fd);        // version
-    readBytes(fd);          // verityRootHash
-    readBytes(fd);          // v3Digest
-    readBytes(fd);          // pkcs7SignatureBlock
-    return readBEInt32(fd); // size of the verity tree
+    readLEInt32(fd);        // version
+    readBytes(fd);          // hashingInfo
+    readBytes(fd);          // signingInfo
+    return readLEInt32(fd); // size of the verity tree
 }
 
 static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) {
@@ -365,13 +364,8 @@
         }
     }
     void onDestroy() final {
-        ALOGE("Sending EXIT to server.");
-        sendRequest(mOutFd, EXIT);
         // Make sure the receiver thread stopped.
         CHECK(!mReceiverThread.joinable());
-
-        mInFd.reset();
-        mOutFd.reset();
     }
 
     // Installation.
@@ -569,13 +563,6 @@
 
     // Streaming.
     bool initStreaming(unique_fd inout) {
-        mInFd.reset(dup(inout));
-        mOutFd.reset(dup(inout));
-        if (mInFd < 0 || mOutFd < 0) {
-            ALOGE("Failed to dup FDs.");
-            return false;
-        }
-
         mEventFd.reset(eventfd(0, EFD_CLOEXEC));
         if (mEventFd < 0) {
             ALOGE("Failed to create eventfd.");
@@ -584,7 +571,7 @@
 
         // Awaiting adb handshake.
         char okay_buf[OKAY.size()];
-        if (!android::base::ReadFully(mInFd, okay_buf, OKAY.size())) {
+        if (!android::base::ReadFully(inout, okay_buf, OKAY.size())) {
             ALOGE("Failed to receive OKAY. Abort.");
             return false;
         }
@@ -594,13 +581,23 @@
             return false;
         }
 
-        mReceiverThread = std::thread([this]() { receiver(); });
+        {
+            std::lock_guard lock{mOutFdLock};
+            mOutFd.reset(::dup(inout));
+            if (mOutFd < 0) {
+                ALOGE("Failed to create streaming fd.");
+            }
+        }
+
+        mReceiverThread =
+                std::thread([this, io = std::move(inout)]() mutable { receiver(std::move(io)); });
         ALOGI("Started streaming...");
         return true;
     }
 
     // IFS callbacks.
     void onPendingReads(dataloader::PendingReads pendingReads) final {
+        std::lock_guard lock{mOutFdLock};
         CHECK(mIfs);
         for (auto&& pendingRead : pendingReads) {
             const android::dataloader::FileId& fileId = pendingRead.id;
@@ -626,12 +623,12 @@
         }
     }
 
-    void receiver() {
+    void receiver(unique_fd inout) {
         std::vector<uint8_t> data;
         std::vector<IncFsDataBlock> instructions;
         std::unordered_map<FileIdx, unique_fd> writeFds;
         while (!mStopReceiving) {
-            const int res = waitForDataOrSignal(mInFd, mEventFd);
+            const int res = waitForDataOrSignal(inout, mEventFd);
             if (res == 0) {
                 continue;
             }
@@ -641,10 +638,11 @@
                 break;
             }
             if (res == mEventFd) {
-                ALOGE("Received stop signal. Exit.");
+                ALOGE("Received stop signal. Sending EXIT to server.");
+                sendRequest(inout, EXIT);
                 break;
             }
-            if (!readChunk(mInFd, data)) {
+            if (!readChunk(inout, data)) {
                 ALOGE("Failed to read a message. Abort.");
                 mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
                 break;
@@ -657,7 +655,7 @@
                     ALOGI("Stop signal received. Sending exit command (remaining bytes: %d).",
                           int(remainingData.size()));
 
-                    sendRequest(mOutFd, EXIT);
+                    sendRequest(inout, EXIT);
                     mStopReceiving = true;
                     break;
                 }
@@ -700,6 +698,11 @@
             writeInstructions(instructions);
         }
         writeInstructions(instructions);
+
+        {
+            std::lock_guard lock{mOutFdLock};
+            mOutFd.reset();
+        }
     }
 
     void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
@@ -743,7 +746,7 @@
     std::string mArgs;
     android::dataloader::FilesystemConnectorPtr mIfs = nullptr;
     android::dataloader::StatusListenerPtr mStatusListener = nullptr;
-    android::base::unique_fd mInFd;
+    std::mutex mOutFdLock;
     android::base::unique_fd mOutFd;
     android::base::unique_fd mEventFd;
     std::thread mReceiverThread;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 239a101..fe05d4e 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -178,6 +178,92 @@
     return isOk;
 }
 
+enum class HalSupport {
+    UNKNOWN = 0,
+    ON,
+    OFF,
+};
+
+static void setPowerBoostWithHandle(sp<IPowerAidl> handle, Boost boost, int32_t durationMs) {
+    // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT.
+    // Need to increase the array size if more boost supported.
+    static std::array<std::atomic<HalSupport>,
+                      static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT) + 1>
+            boostSupportedArray = {HalSupport::UNKNOWN};
+
+    // Quick return if boost is not supported by HAL
+    if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
+        boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
+        ALOGV("Skipped setPowerBoost %s because HAL doesn't support it", toString(boost).c_str());
+        return;
+    }
+
+    if (boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
+        bool isSupported = false;
+        handle->isBoostSupported(boost, &isSupported);
+        boostSupportedArray[static_cast<int32_t>(boost)] =
+            isSupported ? HalSupport::ON : HalSupport::OFF;
+        if (!isSupported) {
+            ALOGV("Skipped setPowerBoost %s because HAL doesn't support it",
+                  toString(boost).c_str());
+            return;
+        }
+    }
+
+    auto ret = handle->setBoost(boost, durationMs);
+    processPowerHalReturn(ret.isOk(), "setPowerBoost");
+}
+
+static void setPowerBoost(Boost boost, int32_t durationMs) {
+    std::unique_lock<std::mutex> lock(gPowerHalMutex);
+    if (connectPowerHalLocked() != HalVersion::AIDL) {
+        ALOGV("Power HAL AIDL not available");
+        return;
+    }
+    sp<IPowerAidl> handle = gPowerHalAidl_;
+    lock.unlock();
+    setPowerBoostWithHandle(handle, boost, durationMs);
+}
+
+static void setPowerModeWithHandle(sp<IPowerAidl> handle, Mode mode, bool enabled) {
+    // Android framework only sends mode upto DISPLAY_INACTIVE.
+    // Need to increase the array if more mode supported.
+    static std::array<std::atomic<HalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE) + 1>
+            modeSupportedArray = {HalSupport::UNKNOWN};
+
+    // Quick return if mode is not supported by HAL
+    if (mode > Mode::DISPLAY_INACTIVE ||
+        modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
+        ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
+        return;
+    }
+
+    if (modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
+        bool isSupported = false;
+        handle->isModeSupported(mode, &isSupported);
+        modeSupportedArray[static_cast<int32_t>(mode)] =
+            isSupported ? HalSupport::ON : HalSupport::OFF;
+        if (!isSupported) {
+            ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
+            return;
+        }
+    }
+
+    auto ret = handle->setMode(mode, enabled);
+    processPowerHalReturn(ret.isOk(), "setPowerMode");
+}
+
+static void setPowerMode(Mode mode, bool enabled) {
+    std::unique_lock<std::mutex> lock(gPowerHalMutex);
+    if (connectPowerHalLocked() != HalVersion::AIDL) {
+        ALOGV("Power HAL AIDL not available");
+        return;
+    }
+    sp<IPowerAidl> handle = gPowerHalAidl_;
+    lock.unlock();
+    setPowerModeWithHandle(handle, mode, enabled);
+}
+
 static void sendPowerHint(PowerHint hintId, uint32_t data) {
     std::unique_lock<std::mutex> lock(gPowerHalMutex);
     switch (connectPowerHalLocked()) {
@@ -201,14 +287,28 @@
             if (hintId == PowerHint::INTERACTION) {
                 sp<IPowerAidl> handle = gPowerHalAidl_;
                 lock.unlock();
-                auto ret = handle->setBoost(Boost::INTERACTION, data);
-                processPowerHalReturn(ret.isOk(), "setBoost");
+                setPowerBoostWithHandle(handle, Boost::INTERACTION, data);
                 break;
             } else if (hintId == PowerHint::LAUNCH) {
                 sp<IPowerAidl> handle = gPowerHalAidl_;
                 lock.unlock();
-                auto ret = handle->setMode(Mode::LAUNCH, static_cast<bool>(data));
-                processPowerHalReturn(ret.isOk(), "setMode");
+                setPowerModeWithHandle(handle, Mode::LAUNCH, static_cast<bool>(data));
+                break;
+            } else if (hintId == PowerHint::LOW_POWER) {
+                sp<IPowerAidl> handle = gPowerHalAidl_;
+                lock.unlock();
+                setPowerModeWithHandle(handle, Mode::LOW_POWER, static_cast<bool>(data));
+                break;
+            } else if (hintId == PowerHint::SUSTAINED_PERFORMANCE) {
+                sp<IPowerAidl> handle = gPowerHalAidl_;
+                lock.unlock();
+                setPowerModeWithHandle(handle, Mode::SUSTAINED_PERFORMANCE,
+                                       static_cast<bool>(data));
+                break;
+            } else if (hintId == PowerHint::VR_MODE) {
+                sp<IPowerAidl> handle = gPowerHalAidl_;
+                lock.unlock();
+                setPowerModeWithHandle(handle, Mode::VR, static_cast<bool>(data));
                 break;
             } else {
                 ALOGE("Unsupported power hint: %s.", toString(hintId).c_str());
@@ -223,87 +323,6 @@
     SurfaceComposerClient::notifyPowerHint(static_cast<int32_t>(hintId));
 }
 
-enum class HalSupport {
-    UNKNOWN = 0,
-    ON,
-    OFF,
-};
-
-static void setPowerBoost(Boost boost, int32_t durationMs) {
-    // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT.
-    // Need to increase the array size if more boost supported.
-    static std::array<std::atomic<HalSupport>,
-                      static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT) + 1>
-        boostSupportedArray = {HalSupport::UNKNOWN};
-
-    // Quick return if boost is not supported by HAL
-    if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
-        boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
-        ALOGV("Skipped setPowerBoost %s because HAL doesn't support it", toString(boost).c_str());
-        return;
-    }
-
-    std::unique_lock<std::mutex> lock(gPowerHalMutex);
-    if (connectPowerHalLocked() != HalVersion::AIDL) {
-        ALOGV("Power HAL AIDL not available");
-        return;
-    }
-    sp<IPowerAidl> handle = gPowerHalAidl_;
-    lock.unlock();
-
-    if (boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
-        bool isSupported = false;
-        handle->isBoostSupported(boost, &isSupported);
-        boostSupportedArray[static_cast<int32_t>(boost)] =
-            isSupported ? HalSupport::ON : HalSupport::OFF;
-        if (!isSupported) {
-            ALOGV("Skipped setPowerBoost %s because HAL doesn't support it",
-                  toString(boost).c_str());
-            return;
-        }
-    }
-
-    auto ret = handle->setBoost(boost, durationMs);
-    processPowerHalReturn(ret.isOk(), "setPowerBoost");
-}
-
-static void setPowerMode(Mode mode, bool enabled) {
-    // Android framework only sends mode upto DISPLAY_INACTIVE.
-    // Need to increase the array if more mode supported.
-    static std::array<std::atomic<HalSupport>,
-                      static_cast<int32_t>(Mode::DISPLAY_INACTIVE) + 1>
-        modeSupportedArray = {HalSupport::UNKNOWN};
-
-    // Quick return if mode is not supported by HAL
-    if (mode > Mode::DISPLAY_INACTIVE ||
-        modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
-        ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
-        return;
-    }
-
-    std::unique_lock<std::mutex> lock(gPowerHalMutex);
-    if (connectPowerHalLocked() != HalVersion::AIDL) {
-        ALOGV("Power HAL AIDL not available");
-        return;
-    }
-    sp<IPowerAidl> handle = gPowerHalAidl_;
-    lock.unlock();
-
-    if (modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
-        bool isSupported = false;
-        handle->isModeSupported(mode, &isSupported);
-        modeSupportedArray[static_cast<int32_t>(mode)] =
-            isSupported ? HalSupport::ON : HalSupport::OFF;
-        if (!isSupported) {
-            ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
-            return;
-        }
-    }
-
-    auto ret = handle->setMode(mode, enabled);
-    processPowerHalReturn(ret.isOk(), "setPowerMode");
-}
-
 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
     if (gPowerManagerServiceObj) {
         // Throttle calls into user activity by event type.
@@ -426,8 +445,7 @@
         case HalVersion::AIDL: {
             sp<IPowerAidl> handle = gPowerHalAidl_;
             lock.unlock();
-            auto ret = handle->setMode(Mode::INTERACTIVE, enable);
-            processPowerHalReturn(ret.isOk(), "setMode");
+            setPowerModeWithHandle(handle, Mode::INTERACTIVE, enable);
             return;
         }
         default: {
@@ -481,8 +499,9 @@
             return;
         }
         case HalVersion::AIDL: {
-            auto ret = gPowerHalAidl_->setMode(Mode::DOUBLE_TAP_TO_WAKE, static_cast<bool>(data));
-            processPowerHalReturn(ret.isOk(), "setMode");
+            sp<IPowerAidl> handle = gPowerHalAidl_;
+            lock.unlock();
+            setPowerModeWithHandle(handle, Mode::DOUBLE_TAP_TO_WAKE, static_cast<bool>(data));
             return;
         }
         default: {
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index be11b86..0277f16 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -25,17 +25,14 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/fsverity.h>
+#include <linux/stat.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <type_traits>
-
 #include <android-base/unique_fd.h>
 
-const int kSha256Bytes = 32;
-
 namespace android {
 
 namespace {
@@ -69,30 +66,28 @@
     return 0;
 }
 
-int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
-    using Storage = std::aligned_storage_t<sizeof(fsverity_digest) + kSha256Bytes>;
-
-    Storage bytes;
-    fsverity_digest *data = reinterpret_cast<fsverity_digest *>(&bytes);
-    data->digest_size = kSha256Bytes;  // the only input/output parameter
-
+// Returns whether the file has fs-verity enabled.
+// 0 if it is not present, 1 if is present, and -errno if there was an error.
+int statxForFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath) {
     ScopedUtfChars path(env, filePath);
-    if (path.c_str() == nullptr) {
-        return EINVAL;
+
+    struct statx out = {};
+    if (statx(AT_FDCWD, path.c_str(), 0 /* flags */, STATX_ALL, &out) != 0) {
+        return -errno;
     }
-    ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
-    if (rfd.get() < 0) {
-        return errno;
+
+    // Sanity check.
+    if ((out.stx_attributes_mask & STATX_ATTR_VERITY) == 0) {
+        ALOGE("Unexpected, STATX_ATTR_VERITY not supported by kernel");
+        return -ENOSYS;
     }
-    if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
-        return errno;
-    }
-    return 0;
+
+    return (out.stx_attributes & STATX_ATTR_VERITY) != 0;
 }
 
 const JNINativeMethod sMethods[] = {
-    { "enableFsverityNative", "(Ljava/lang/String;[B)I", (void *)enableFsverity },
-    { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
+        {"enableFsverityNative", "(Ljava/lang/String;[B)I", (void *)enableFsverity},
+        {"statxForFsverityNative", "(Ljava/lang/String;)I", (void *)statxForFsverity},
 };
 
 }  // namespace
diff --git a/services/core/jni/com_android_server_tv_GamepadKeys.h b/services/core/jni/com_android_server_tv_GamepadKeys.h
new file mode 100644
index 0000000..11fc903
--- /dev/null
+++ b/services/core/jni/com_android_server_tv_GamepadKeys.h
@@ -0,0 +1,79 @@
+#ifndef ANDROIDTVREMOTE_SERVICE_JNI_GAMEPAD_KEYS_H_
+#define ANDROIDTVREMOTE_SERVICE_JNI_GAMEPAD_KEYS_H_
+
+#include <linux/input.h>
+
+namespace android {
+
+// Follows the W3 spec for gamepad buttons and their corresponding mapping into
+// Linux keycodes. Note that gamepads are generally not very well standardized
+// and various controllers will result in different buttons. This mapping tries
+// to be reasonable.
+//
+// W3 Button spec: https://www.w3.org/TR/gamepad/#remapping
+//
+// Standard gamepad keycodes are added plus 2 additional buttons (e.g. Stadia
+// has "Assistant" and "Share", PS4 has the touchpad button).
+//
+// To generate this list, PS4, XBox, Stadia and Nintendo Switch Pro were tested.
+static const int GAMEPAD_KEY_CODES[19] = {
+        // Right-side buttons. A/B/X/Y or circle/triangle/square/X or similar
+        BTN_A, // "South", A, GAMEPAD and SOUTH have the same constant
+        BTN_B, // "East", BTN_B, BTN_EAST have the same constant
+        BTN_X, // "West", Note that this maps to X and NORTH in constants
+        BTN_Y, // "North", Note that this maps to Y and WEST in constants
+
+        BTN_TL, // "Left Bumper" / "L1" - Nintendo sends BTN_WEST instead
+        BTN_TR, // "Right Bumper" / "R1" - Nintendo sends BTN_Z instead
+
+        // For triggers, gamepads vary:
+        //   - Stadia sends analog values over ABS_GAS/ABS_BRAKE and sends
+        //     TriggerHappy3/4 as digital presses
+        //   - PS4 and Xbox send analog values as ABS_Z/ABS_RZ
+        //   - Nintendo Pro sends BTN_TL/BTN_TR (since bumpers behave differently)
+        // As placeholders we chose the stadia trigger-happy values since TL/TR are
+        // sent for bumper button presses
+        BTN_TRIGGER_HAPPY4, // "Left Trigger" / "L2"
+        BTN_TRIGGER_HAPPY3, // "Right Trigger" / "R2"
+
+        BTN_SELECT, // "Select/Back". Often "options" or similar
+        BTN_START,  // "Start/forward". Often "hamburger" icon
+
+        BTN_THUMBL, // "Left Joystick Pressed"
+        BTN_THUMBR, // "Right Joystick Pressed"
+
+        // For DPads, gamepads generally only send axis changes
+        // on ABS_HAT0X and ABS_HAT0Y.
+        KEY_UP,    // "Digital Pad up"
+        KEY_DOWN,  // "Digital Pad down"
+        KEY_LEFT,  // "Digital Pad left"
+        KEY_RIGHT, // "Digital Pad right"
+
+        BTN_MODE, // "Main button" (Stadia/PS/XBOX/Home)
+
+        BTN_TRIGGER_HAPPY1, // Extra button: "Assistant" for Stadia
+        BTN_TRIGGER_HAPPY2, // Extra button: "Share" for Stadia
+};
+
+// Defines information for an axis.
+struct Axis {
+    int number;
+    int rangeMin;
+    int rangeMax;
+};
+
+// List of all axes supported by a gamepad
+static const Axis GAMEPAD_AXES[] = {
+        {ABS_X, 0, 254},    // Left joystick X
+        {ABS_Y, 0, 254},    // Left joystick Y
+        {ABS_RX, 0, 254},   // Right joystick X
+        {ABS_RY, 0, 254},   // Right joystick Y
+        {ABS_Z, 0, 254},    // Left trigger
+        {ABS_RZ, 0, 254},   // Right trigger
+        {ABS_HAT0X, -1, 1}, // DPad X
+        {ABS_HAT0Y, -1, 1}, // DPad Y
+};
+
+} // namespace android
+
+#endif // ANDROIDTVREMOTE_SERVICE_JNI_GAMEPAD_KEYS_H_
diff --git a/services/core/jni/com_android_server_tv_TvKeys.h b/services/core/jni/com_android_server_tv_TvKeys.h
index 4895f34..7eacdf6 100644
--- a/services/core/jni/com_android_server_tv_TvKeys.h
+++ b/services/core/jni/com_android_server_tv_TvKeys.h
@@ -110,4 +110,4 @@
 
 } // namespace android
 
-#endif // SERVICE_JNI_KEYS_H_
+#endif // ANDROIDTVREMOTE_SERVICE_JNI_KEYS_H_
diff --git a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
index c832c18..0e96bd7 100644
--- a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
+++ b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "TvRemote-native-uiBridge"
 
+#include "com_android_server_tv_GamepadKeys.h"
 #include "com_android_server_tv_TvKeys.h"
 
 #include "jni.h"
@@ -92,27 +93,156 @@
     }
 }
 
+static const int kInvalidFileDescriptor = -1;
+
+// Convenience class to manage an opened /dev/uinput device
+class UInputDescriptor {
+public:
+    UInputDescriptor() : mFd(kInvalidFileDescriptor) {
+        memset(&mUinputDescriptor, 0, sizeof(mUinputDescriptor));
+    }
+
+    // Auto-closes any open /dev/uinput descriptor unless detached.
+    ~UInputDescriptor();
+
+    // Open /dev/uinput and prepare to register
+    // the device with the given name and unique Id
+    bool Open(const char* name, const char* uniqueId);
+
+    // Checks if the current file descriptor is valid
+    bool IsValid() const { return mFd != kInvalidFileDescriptor; }
+
+    void EnableKey(int keyCode);
+
+    void EnableAxesEvents();
+    void EnableAxis(int axis, int rangeMin, int rangeMax);
+
+    bool Create();
+
+    // Detaches from the current file descriptor
+    // Returns the file descriptor for /dev/uniput
+    int Detach();
+
+private:
+    int mFd;
+    struct uinput_user_dev mUinputDescriptor;
+};
+
+UInputDescriptor::~UInputDescriptor() {
+    if (mFd != kInvalidFileDescriptor) {
+        close(mFd);
+        mFd = kInvalidFileDescriptor;
+    }
+}
+
+int UInputDescriptor::Detach() {
+    int fd = mFd;
+    mFd = kInvalidFileDescriptor;
+    return fd;
+}
+
+bool UInputDescriptor::Open(const char* name, const char* uniqueId) {
+    if (IsValid()) {
+        ALOGE("UInput device already open");
+        return false;
+    }
+
+    mFd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
+    if (mFd < 0) {
+        ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
+        mFd = kInvalidFileDescriptor;
+        return false;
+    }
+
+    // write device unique id to the phys property
+    ioctl(mFd, UI_SET_PHYS, uniqueId);
+
+    memset(&mUinputDescriptor, 0, sizeof(mUinputDescriptor));
+    strlcpy(mUinputDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
+    mUinputDescriptor.id.version = 1;
+    mUinputDescriptor.id.bustype = BUS_VIRTUAL;
+
+    // All UInput devices we use process keys
+    ioctl(mFd, UI_SET_EVBIT, EV_KEY);
+
+    return true;
+}
+
+void UInputDescriptor::EnableKey(int keyCode) {
+    ioctl(mFd, UI_SET_KEYBIT, keyCode);
+}
+
+void UInputDescriptor::EnableAxesEvents() {
+    ioctl(mFd, UI_SET_EVBIT, EV_ABS);
+}
+
+void UInputDescriptor::EnableAxis(int axis, int rangeMin, int rangeMax) {
+    if ((axis < 0) || (axis >= NELEM(mUinputDescriptor.absmin))) {
+        ALOGE("Invalid axis number: %d", axis);
+        return;
+    }
+
+    if (ioctl(mFd, UI_SET_ABSBIT, axis) != 0) {
+        ALOGE("Failed to set absbit for %d", axis);
+    }
+
+    mUinputDescriptor.absmin[axis] = rangeMin;
+    mUinputDescriptor.absmax[axis] = rangeMax;
+    mUinputDescriptor.absfuzz[axis] = 0;
+    mUinputDescriptor.absflat[axis] = 0;
+}
+
+bool UInputDescriptor::Create() {
+    // register the input device
+    if (write(mFd, &mUinputDescriptor, sizeof(mUinputDescriptor)) != sizeof(mUinputDescriptor)) {
+        ALOGE("Cannot write uinput_user_dev to fd %d: %s.", mFd, strerror(errno));
+        return false;
+    }
+
+    if (ioctl(mFd, UI_DEV_CREATE) != 0) {
+        ALOGE("Unable to create uinput device: %s.", strerror(errno));
+        return false;
+    }
+
+    ALOGV("Created uinput device, fd=%d.", mFd);
+
+    return true;
+}
+
 class NativeConnection {
 public:
+    enum class ConnectionType {
+        kRemoteDevice,
+        kGamepadDevice,
+    };
+
     ~NativeConnection();
 
     static NativeConnection* open(const char* name, const char* uniqueId,
             int32_t width, int32_t height, int32_t maxPointerId);
 
+    static NativeConnection* openGamepad(const char* name, const char* uniqueId);
+
     void sendEvent(int32_t type, int32_t code, int32_t value);
 
     int32_t getMaxPointers() const { return mMaxPointers; }
 
+    ConnectionType getType() const { return mType; }
+
+    bool IsGamepad() const { return getType() == ConnectionType::kGamepadDevice; }
+
+    bool IsRemote() const { return getType() == ConnectionType::kRemoteDevice; }
+
 private:
-    NativeConnection(int fd, int32_t maxPointers);
+    NativeConnection(int fd, int32_t maxPointers, ConnectionType type);
 
     const int mFd;
     const int32_t mMaxPointers;
+    const ConnectionType mType;
 };
 
-NativeConnection::NativeConnection(int fd, int32_t maxPointers) :
-        mFd(fd), mMaxPointers(maxPointers) {
-}
+NativeConnection::NativeConnection(int fd, int32_t maxPointers, ConnectionType type)
+      : mFd(fd), mMaxPointers(maxPointers), mType(type) {}
 
 NativeConnection::~NativeConnection() {
     ALOGI("Un-Registering uinput device %d.", mFd);
@@ -125,44 +255,50 @@
     ALOGI("Registering uinput device %s: touch pad size %dx%d, "
             "max pointers %d.", name, width, height, maxPointers);
 
-    int fd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
-    if (fd < 0) {
-        ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
-        return nullptr;
-    }
-
-    struct uinput_user_dev uinp;
-    memset(&uinp, 0, sizeof(struct uinput_user_dev));
-    strlcpy(uinp.name, name, UINPUT_MAX_NAME_SIZE);
-    uinp.id.version = 1;
-    uinp.id.bustype = BUS_VIRTUAL;
-
-    // initialize keymap
     initKeysMap();
 
-    // write device unique id to the phys property
-    ioctl(fd, UI_SET_PHYS, uniqueId);
-
-    // set the keys mapped
-    ioctl(fd, UI_SET_EVBIT, EV_KEY);
-    for (size_t i = 0; i < NELEM(KEYS); i++) {
-        ioctl(fd, UI_SET_KEYBIT, KEYS[i].linuxKeyCode);
-    }
-
-    // register the input device
-    if (write(fd, &uinp, sizeof(uinp)) != sizeof(uinp)) {
-        ALOGE("Cannot write uinput_user_dev to fd %d: %s.", fd, strerror(errno));
-        close(fd);
-        return NULL;
-    }
-    if (ioctl(fd, UI_DEV_CREATE) != 0) {
-        ALOGE("Unable to create uinput device: %s.", strerror(errno));
-        close(fd);
+    UInputDescriptor descriptor;
+    if (!descriptor.Open(name, uniqueId)) {
         return nullptr;
     }
 
-    ALOGV("Created uinput device, fd=%d.", fd);
-    return new NativeConnection(fd, maxPointers);
+    // set the keys mapped
+    for (size_t i = 0; i < NELEM(KEYS); i++) {
+        descriptor.EnableKey(KEYS[i].linuxKeyCode);
+    }
+
+    if (!descriptor.Create()) {
+        return nullptr;
+    }
+
+    return new NativeConnection(descriptor.Detach(), maxPointers, ConnectionType::kRemoteDevice);
+}
+
+NativeConnection* NativeConnection::openGamepad(const char* name, const char* uniqueId) {
+    ALOGI("Registering uinput device %s: gamepad", name);
+
+    UInputDescriptor descriptor;
+    if (!descriptor.Open(name, uniqueId)) {
+        return nullptr;
+    }
+
+    // set the keys mapped for gamepads
+    for (size_t i = 0; i < NELEM(GAMEPAD_KEY_CODES); i++) {
+        descriptor.EnableKey(GAMEPAD_KEY_CODES[i]);
+    }
+
+    // define the axes that are required
+    descriptor.EnableAxesEvents();
+    for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
+        const Axis& axis = GAMEPAD_AXES[i];
+        descriptor.EnableAxis(axis.number, axis.rangeMin, axis.rangeMax);
+    }
+
+    if (!descriptor.Create()) {
+        return nullptr;
+    }
+
+    return new NativeConnection(descriptor.Detach(), 0, ConnectionType::kGamepadDevice);
 }
 
 void NativeConnection::sendEvent(int32_t type, int32_t code, int32_t value) {
@@ -174,7 +310,6 @@
     write(mFd, &iev, sizeof(iev));
 }
 
-
 static jlong nativeOpen(JNIEnv* env, jclass clazz,
         jstring nameStr, jstring uniqueIdStr,
         jint width, jint height, jint maxPointers) {
@@ -186,6 +321,14 @@
     return reinterpret_cast<jlong>(connection);
 }
 
+static jlong nativeGamepadOpen(JNIEnv* env, jclass clazz, jstring nameStr, jstring uniqueIdStr) {
+    ScopedUtfChars name(env, nameStr);
+    ScopedUtfChars uniqueId(env, uniqueIdStr);
+
+    NativeConnection* connection = NativeConnection::openGamepad(name.c_str(), uniqueId.c_str());
+    return reinterpret_cast<jlong>(connection);
+}
+
 static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
     delete connection;
@@ -194,6 +337,12 @@
 static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) {
     int32_t code = getLinuxKeyCode(keyCode);
     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    if (connection->IsGamepad()) {
+        ALOGE("Invalid key even for a gamepad - need to send gamepad events");
+        return;
+    }
+
     if (code != KEY_UNKNOWN) {
         connection->sendEvent(EV_KEY, code, down ? 1 : 0);
     } else {
@@ -201,10 +350,44 @@
     }
 }
 
+static void nativeSendGamepadKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyIndex,
+                                 jboolean down) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    if (!connection->IsGamepad()) {
+        ALOGE("Invalid gamepad key for non-gamepad device");
+        return;
+    }
+
+    if ((keyIndex < 0) || (keyIndex >= NELEM(GAMEPAD_KEY_CODES))) {
+        ALOGE("Invalid gamepad key index: %d", keyIndex);
+        return;
+    }
+
+    connection->sendEvent(EV_KEY, GAMEPAD_KEY_CODES[keyIndex], down ? 1 : 0);
+}
+
+static void nativeSendGamepadAxisValue(JNIEnv* env, jclass clazz, jlong ptr, jint axis,
+                                       jint value) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    if (!connection->IsGamepad()) {
+        ALOGE("Invalid axis send for non-gamepad device");
+        return;
+    }
+
+    connection->sendEvent(EV_ABS, axis, value);
+}
+
 static void nativeSendPointerDown(JNIEnv* env, jclass clazz, jlong ptr,
         jint pointerId, jint x, jint y) {
     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
 
+    if (connection->IsGamepad()) {
+        ALOGE("Invalid pointer down event for a gamepad.");
+        return;
+    }
+
     int32_t slot = findSlot(pointerId);
     if (slot == SLOT_UNKNOWN) {
         slot = assignSlot(pointerId);
@@ -221,6 +404,11 @@
         jint pointerId) {
     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
 
+    if (connection->IsGamepad()) {
+        ALOGE("Invalid pointer up event for a gamepad.");
+        return;
+    }
+
     int32_t slot = findSlot(pointerId);
     if (slot != SLOT_UNKNOWN) {
         connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
@@ -238,17 +426,34 @@
     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
 
     // Clear keys.
-    for (size_t i = 0; i < NELEM(KEYS); i++) {
-        connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
-    }
+    if (connection->IsRemote()) {
+        for (size_t i = 0; i < NELEM(KEYS); i++) {
+            connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
+        }
 
-    // Clear pointers.
-    int32_t slot = SLOT_UNKNOWN;
-    for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
-        slot = findSlot(i);
-        if (slot != SLOT_UNKNOWN) {
-            connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
-            connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+        // Clear pointers.
+        int32_t slot = SLOT_UNKNOWN;
+        for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
+            slot = findSlot(i);
+            if (slot != SLOT_UNKNOWN) {
+                connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
+                connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+            }
+        }
+    } else {
+        for (size_t i = 0; i < NELEM(GAMEPAD_KEY_CODES); i++) {
+            connection->sendEvent(EV_KEY, GAMEPAD_KEY_CODES[i], 0);
+        }
+
+        for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
+            const Axis& axis = GAMEPAD_AXES[i];
+            if ((axis.number == ABS_Z) || (axis.number == ABS_RZ)) {
+                // Mark triggers unpressed
+                connection->sendEvent(EV_ABS, axis.number, 0);
+            } else {
+                // Joysticks and dpad rests on center
+                connection->sendEvent(EV_ABS, axis.number, (axis.rangeMin + axis.rangeMax) / 2);
+            }
         }
     }
 
@@ -261,20 +466,16 @@
  */
 
 static JNINativeMethod gUinputBridgeMethods[] = {
-    { "nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J",
-        (void*)nativeOpen },
-    { "nativeClose", "(J)V",
-        (void*)nativeClose },
-    { "nativeSendKey", "(JIZ)V",
-        (void*)nativeSendKey },
-    { "nativeSendPointerDown", "(JIII)V",
-        (void*)nativeSendPointerDown },
-    { "nativeSendPointerUp", "(JI)V",
-        (void*)nativeSendPointerUp },
-    { "nativeClear", "(J)V",
-        (void*)nativeClear },
-    { "nativeSendPointerSync", "(J)V",
-        (void*)nativeSendPointerSync },
+        {"nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J", (void*)nativeOpen},
+        {"nativeGamepadOpen", "(Ljava/lang/String;Ljava/lang/String;)J", (void*)nativeGamepadOpen},
+        {"nativeClose", "(J)V", (void*)nativeClose},
+        {"nativeSendKey", "(JIZ)V", (void*)nativeSendKey},
+        {"nativeSendPointerDown", "(JIII)V", (void*)nativeSendPointerDown},
+        {"nativeSendPointerUp", "(JI)V", (void*)nativeSendPointerUp},
+        {"nativeClear", "(J)V", (void*)nativeClear},
+        {"nativeSendPointerSync", "(J)V", (void*)nativeSendPointerSync},
+        {"nativeSendGamepadKey", "(JIZ)V", (void*)nativeSendGamepadKey},
+        {"nativeSendGamepadAxisValue", "(JII)V", (void*)nativeSendGamepadAxisValue},
 };
 
 int register_android_server_tv_TvUinputBridge(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 312d2d2..f5d2c6a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -86,6 +86,7 @@
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
 import static android.provider.Telephony.Carriers.DPC_URI;
@@ -785,7 +786,7 @@
         List<String> mLockTaskPackages = new ArrayList<>();
 
         // List of packages protected by device owner
-        List<String> mProtectedPackages = new ArrayList<>();
+        List<String> mUserControlDisabledPackages = new ArrayList<>();
 
         // Bitfield of feature flags to be enabled during LockTask mode.
         // We default on the power button menu, in order to be consistent with pre-P behaviour.
@@ -1198,7 +1199,7 @@
         // Whether the admin explicitly requires personal apps to be suspended
         boolean mSuspendPersonalApps = false;
         // Maximum time the profile owned by this admin can be off.
-        long mProfileMaximumTimeOff = 0;
+        long mProfileMaximumTimeOffMillis = 0;
         // Time by which the profile should be turned on according to System.currentTimeMillis().
         long mProfileOffDeadline = 0;
 
@@ -1439,10 +1440,11 @@
             if (mSuspendPersonalApps) {
                 writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps);
             }
-            if (mProfileMaximumTimeOff != 0) {
-                writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF, mProfileMaximumTimeOff);
+            if (mProfileMaximumTimeOffMillis != 0) {
+                writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF,
+                        mProfileMaximumTimeOffMillis);
             }
-            if (mProfileMaximumTimeOff != 0) {
+            if (mProfileMaximumTimeOffMillis != 0) {
                 writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline);
             }
             if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) {
@@ -1691,7 +1693,7 @@
                     mSuspendPersonalApps = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) {
-                    mProfileMaximumTimeOff =
+                    mProfileMaximumTimeOffMillis =
                             Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
                     mProfileOffDeadline =
@@ -1929,8 +1931,8 @@
                 pw.println(mCrossProfilePackages);
             pw.print("mSuspendPersonalApps=");
                 pw.println(mSuspendPersonalApps);
-            pw.print("mProfileMaximumTimeOff=");
-                pw.println(mProfileMaximumTimeOff);
+            pw.print("mProfileMaximumTimeOffMillis=");
+                pw.println(mProfileMaximumTimeOffMillis);
             pw.print("mProfileOffDeadline=");
                 pw.println(mProfileOffDeadline);
             pw.print("mAlwaysOnVpnPackage=");
@@ -3539,8 +3541,8 @@
                 out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT);
             }
 
-            for (int i = 0, size = policy.mProtectedPackages.size(); i < size; i++) {
-                String packageName = policy.mProtectedPackages.get(i);
+            for (int i = 0, size = policy.mUserControlDisabledPackages.size(); i < size; i++) {
+                String packageName = policy.mUserControlDisabledPackages.get(i);
                 out.startTag(null, TAG_PROTECTED_PACKAGES);
                 out.attribute(null, ATTR_NAME, packageName);
                 out.endTag(null, TAG_PROTECTED_PACKAGES);
@@ -3665,7 +3667,7 @@
             policy.mAdminMap.clear();
             policy.mAffiliationIds.clear();
             policy.mOwnerInstalledCaCerts.clear();
-            policy.mProtectedPackages.clear();
+            policy.mUserControlDisabledPackages.clear();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -3767,7 +3769,8 @@
                 } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
                     policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS));
                 } else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
-                    policy.mProtectedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
+                    policy.mUserControlDisabledPackages.add(
+                            parser.getAttributeValue(null, ATTR_NAME));
                 } else if (TAG_APPS_SUSPENDED.equals(tag)) {
                     policy.mAppsSuspended =
                             Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE));
@@ -3802,7 +3805,7 @@
         updateMaximumTimeToLockLocked(userHandle);
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
         updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle);
-        updateProtectedPackagesLocked(policy.mProtectedPackages);
+        updateUserControlDisabledPackagesLocked(policy.mUserControlDisabledPackages);
         if (policy.mStatusBarDisabled) {
             setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
         }
@@ -3828,7 +3831,7 @@
         }
     }
 
-    private void updateProtectedPackagesLocked(List<String> packages) {
+    private void updateUserControlDisabledPackagesLocked(List<String> packages) {
         mInjector.getPackageManagerInternal().setDeviceOwnerProtectedPackages(packages);
     }
 
@@ -5874,6 +5877,14 @@
         }
     }
 
+    private void enforceNetworkStackOrProfileOrDeviceOwner(ComponentName who) {
+        if (mContext.checkCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)
+                == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+        enforceProfileOrDeviceOwner(who);
+    }
+
     private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) {
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(
@@ -6870,7 +6881,7 @@
 
     @Override
     public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
-        enforceProfileOrDeviceOwner(admin);
+        enforceNetworkStackOrProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
         return mInjector.binderWithCleanCallingIdentity(
@@ -7786,7 +7797,7 @@
      * Set whether auto time is enabled on the device.
      */
     @Override
-    public void setAutoTime(ComponentName who, boolean enabled) {
+    public void setAutoTimeEnabled(ComponentName who, boolean enabled) {
         if (!mHasFeature) {
             return;
         }
@@ -7807,7 +7818,7 @@
      * Returns whether auto time is used on the device or not.
      */
     @Override
-    public boolean getAutoTime(ComponentName who) {
+    public boolean getAutoTimeEnabled(ComponentName who) {
         if (!mHasFeature) {
             return false;
         }
@@ -7821,7 +7832,7 @@
      * Set whether auto time zone is enabled on the device.
      */
     @Override
-    public void setAutoTimeZone(ComponentName who, boolean enabled) {
+    public void setAutoTimeZoneEnabled(ComponentName who, boolean enabled) {
         if (!mHasFeature) {
             return;
         }
@@ -7842,7 +7853,7 @@
      * Returns whether auto time zone is used on the device or not.
      */
     @Override
-    public boolean getAutoTimeZone(ComponentName who) {
+    public boolean getAutoTimeZoneEnabled(ComponentName who) {
         if (!mHasFeature) {
             return false;
         }
@@ -8820,8 +8831,8 @@
         policy.mLockTaskPackages.clear();
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userId);
         policy.mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
-        policy.mProtectedPackages.clear();
-        updateProtectedPackagesLocked(policy.mProtectedPackages);
+        policy.mUserControlDisabledPackages.clear();
+        updateUserControlDisabledPackagesLocked(policy.mUserControlDisabledPackages);
         saveSettingsLocked(userId);
 
         try {
@@ -9574,7 +9585,8 @@
             pw.println();
             pw.increaseIndent();
             pw.print("mPasswordOwner="); pw.println(policy.mPasswordOwner);
-            pw.print("mProtectedPackages="); pw.println(policy.mProtectedPackages);
+            pw.print("mUserControlDisabledPackages=");
+            pw.println(policy.mUserControlDisabledPackages);
             pw.print("mAppsSuspended="); pw.println(policy.mAppsSuspended);
             pw.decreaseIndent();
         }
@@ -15549,39 +15561,39 @@
     }
 
     @Override
-    public void setProtectedPackages(ComponentName who, List<String> packages) {
+    public void setUserControlDisabledPackages(ComponentName who, List<String> packages) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         Preconditions.checkNotNull(packages, "packages is null");
 
         enforceDeviceOwner(who);
         synchronized (getLockObject()) {
             final int userHandle = mInjector.userHandleGetCallingUserId();
-            setProtectedPackagesLocked(userHandle, packages);
+            setUserControlDisabledPackagesLocked(userHandle, packages);
             DevicePolicyEventLogger
-                    .createEvent(DevicePolicyEnums.SET_PACKAGES_PROTECTED)
+                    .createEvent(DevicePolicyEnums.SET_USER_CONTROL_DISABLED_PACKAGES)
                     .setAdmin(who)
                     .setStrings(packages.toArray(new String[packages.size()]))
                     .write();
         }
     }
 
-    private void setProtectedPackagesLocked(int userHandle, List<String> packages) {
+    private void setUserControlDisabledPackagesLocked(int userHandle, List<String> packages) {
         final DevicePolicyData policy = getUserData(userHandle);
-        policy.mProtectedPackages = packages;
+        policy.mUserControlDisabledPackages = packages;
 
         // Store the settings persistently.
         saveSettingsLocked(userHandle);
-        updateProtectedPackagesLocked(packages);
+        updateUserControlDisabledPackagesLocked(packages);
     }
 
     @Override
-    public List<String> getProtectedPackages(ComponentName who) {
+    public List<String> getUserControlDisabledPackages(ComponentName who) {
         Preconditions.checkNotNull(who, "ComponentName is null");
 
         enforceDeviceOwner(who);
         final int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
         synchronized (getLockObject()) {
-            final List<String> packages = getUserData(userHandle).mProtectedPackages;
+            final List<String> packages = getUserData(userHandle).mUserControlDisabledPackages;
             return packages == null ? Collections.EMPTY_LIST : packages;
         }
     }
@@ -15716,18 +15728,18 @@
         }
         boolean shouldSaveSettings = false;
         if (profileOwner.mProfileOffDeadline != 0
-                && (profileOwner.mProfileMaximumTimeOff == 0 || unlocked)) {
+                && (profileOwner.mProfileMaximumTimeOffMillis == 0 || unlocked)) {
             // There is a deadline but either there is no policy or the profile is unlocked -> clear
             // the deadline.
             Slog.i(LOG_TAG, "Profile off deadline is reset to zero");
             profileOwner.mProfileOffDeadline = 0;
             shouldSaveSettings = true;
         } else if (profileOwner.mProfileOffDeadline == 0
-                && (profileOwner.mProfileMaximumTimeOff != 0 && !unlocked)) {
+                && (profileOwner.mProfileMaximumTimeOffMillis != 0 && !unlocked)) {
             // There profile is locked and there is a policy, but the deadline is not set -> set the
             // deadline.
             Slog.i(LOG_TAG, "Profile off deadline is set.");
-            profileOwner.mProfileOffDeadline = now + profileOwner.mProfileMaximumTimeOff;
+            profileOwner.mProfileOffDeadline = now + profileOwner.mProfileMaximumTimeOffMillis;
             shouldSaveSettings = true;
         }
 
@@ -15828,7 +15840,7 @@
     }
 
     @Override
-    public void setManagedProfileMaximumTimeOff(ComponentName who, long timeoutMs) {
+    public void setManagedProfileMaximumTimeOff(ComponentName who, long timeoutMillis) {
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -15837,10 +15849,10 @@
             // DO shouldn't be able to use this method.
             enforceProfileOwnerOfOrganizationOwnedDevice(admin);
             enforceHandlesCheckPolicyComplianceIntent(userId, admin.info.getPackageName());
-            if (admin.mProfileMaximumTimeOff == timeoutMs) {
+            if (admin.mProfileMaximumTimeOffMillis == timeoutMillis) {
                 return;
             }
-            admin.mProfileMaximumTimeOff = timeoutMs;
+            admin.mProfileMaximumTimeOffMillis = timeoutMillis;
             saveSettingsLocked(userId);
         }
 
@@ -15850,7 +15862,7 @@
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_MANAGED_PROFILE_MAXIMUM_TIME_OFF)
                 .setAdmin(who)
-                .setTimePeriod(timeoutMs)
+                .setTimePeriod(timeoutMillis)
                 .write();
     }
 
@@ -15874,7 +15886,7 @@
                     false /* parent */);
             // DO shouldn't be able to use this method.
             enforceProfileOwnerOfOrganizationOwnedDevice(admin);
-            return admin.mProfileMaximumTimeOff;
+            return admin.mProfileMaximumTimeOffMillis;
         }
     }
 
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 3fcb57a..2dbbc5a 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -178,15 +178,9 @@
     nfp.size = params.size;
     nfp.metadata = {(const char*)params.metadata.data(), (IncFsSize)params.metadata.size()};
     if (!params.signature) {
-        nfp.verification = {};
+        nfp.signature = {};
     } else {
-        nfp.verification.hashAlgorithm = IncFsHashAlgortithm(params.signature->hashAlgorithm);
-        nfp.verification.rootHash = {(const char*)params.signature->rootHash.data(),
-                                     (IncFsSize)params.signature->rootHash.size()};
-        nfp.verification.additionalData = {(const char*)params.signature->additionalData.data(),
-                                           (IncFsSize)params.signature->additionalData.size()};
-        nfp.verification.signature = {(const char*)params.signature->signature.data(),
-                                      (IncFsSize)params.signature->signature.size()};
+        nfp.signature = {(const char*)params.signature->data(), (IncFsSize)params.signature->size()};
     }
     return {0, id, nfp};
 }
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index cccd0133..7275936 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1155,7 +1155,7 @@
         // Create new lib file without signature info
         incfs::NewFileParams libFileParams{};
         libFileParams.size = uncompressedLen;
-        libFileParams.verification.hashAlgorithm = INCFS_HASH_NONE;
+        libFileParams.signature = {};
         // Metadata of the new lib file is its relative path
         IncFsSpan libFileMetadata;
         libFileMetadata.data = targetLibPath.c_str();
diff --git a/services/net/Android.bp b/services/net/Android.bp
index dbc2df8..c54102f 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -20,6 +20,44 @@
     ],
 }
 
+// Version of services.net for usage by the wifi mainline module.
+// Note: This is compiled against module_current.
+// TODO(b/145825329): This should be moved to networkstack-client,
+// with dependencies moved to frameworks/libs/net right.
+java_library {
+    name: "services.net-module-wifi",
+    srcs: [
+        ":framework-services-net-module-wifi-shared-srcs",
+        ":net-module-utils-srcs",
+        "java/android/net/ip/IpClientCallbacks.java",
+        "java/android/net/ip/IpClientManager.java",
+        "java/android/net/ip/IpClientUtil.java",
+        "java/android/net/util/KeepalivePacketDataUtil.java",
+        "java/android/net/util/NetworkConstants.java",
+        "java/android/net/IpMemoryStore.java",
+        "java/android/net/NetworkMonitorManager.java",
+        "java/android/net/TcpKeepalivePacketData.java",
+    ],
+    sdk_version: "module_current",
+    libs: [
+        "unsupportedappusage",
+    ],
+    static_libs: [
+        "dnsresolver_aidl_interface-V2-java",
+        "netd_aidl_interface-unstable-java",
+        "netlink-client",
+        "networkstack-client",
+        "net-utils-services-common",
+    ],
+    apex_available: [
+        "com.android.wifi",
+    ],
+    visibility: [
+        "//frameworks/opt/net/wifi/service",
+        "//frameworks/opt/net/wifi/tests/wifitests",
+    ],
+}
+
 filegroup {
     name: "services-tethering-shared-srcs",
     srcs: [
diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java
index dcefb53..8df2e0d 100644
--- a/services/net/java/android/net/IpMemoryStore.java
+++ b/services/net/java/android/net/IpMemoryStore.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.networkstack.ModuleNetworkStackClient;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -41,7 +42,7 @@
         super(context);
         mService = new CompletableFuture<>();
         mTailNode = new AtomicReference<CompletableFuture<IIpMemoryStore>>(mService);
-        getNetworkStackClient().fetchIpMemoryStore(
+        getModuleNetworkStackClient(context).fetchIpMemoryStore(
                 new IIpMemoryStoreCallbacks.Stub() {
                     @Override
                     public void onIpMemoryStoreFetched(@NonNull final IIpMemoryStore memoryStore) {
@@ -85,8 +86,8 @@
     }
 
     @VisibleForTesting
-    protected NetworkStackClient getNetworkStackClient() {
-        return NetworkStackClient.getInstance();
+    protected ModuleNetworkStackClient getModuleNetworkStackClient(Context context) {
+        return ModuleNetworkStackClient.getInstance(context);
     }
 
     /** Gets an instance of the memory store */
diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
index aad75ae..fcf3a56 100644
--- a/services/net/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -74,6 +74,19 @@
         ipTtl = tcpDetails.ttl;
     }
 
+    private TcpKeepalivePacketData(final InetAddress srcAddress, int srcPort,
+            final InetAddress dstAddress, int dstPort, final byte[] data, int tcpSeq,
+            int tcpAck, int tcpWnd, int tcpWndScale, int ipTos, int ipTtl)
+            throws InvalidPacketException {
+        super(srcAddress, srcPort, dstAddress, dstPort, data);
+        this.tcpSeq = tcpSeq;
+        this.tcpAck = tcpAck;
+        this.tcpWnd = tcpWnd;
+        this.tcpWndScale = tcpWndScale;
+        this.ipTos = ipTos;
+        this.ipTtl = ipTtl;
+    }
+
     /**
      * Factory method to create tcp keepalive packet structure.
      */
@@ -169,7 +182,11 @@
 
     /** Write to parcel. */
     public void writeToParcel(Parcel out, int flags) {
-        super.writeToParcel(out, flags);
+        out.writeString(srcAddress.getHostAddress());
+        out.writeString(dstAddress.getHostAddress());
+        out.writeInt(srcPort);
+        out.writeInt(dstPort);
+        out.writeByteArray(getPacket());
         out.writeInt(tcpSeq);
         out.writeInt(tcpAck);
         out.writeInt(tcpWnd);
@@ -178,21 +195,32 @@
         out.writeInt(ipTtl);
     }
 
-    private TcpKeepalivePacketData(Parcel in) {
-        super(in);
-        tcpSeq = in.readInt();
-        tcpAck = in.readInt();
-        tcpWnd = in.readInt();
-        tcpWndScale = in.readInt();
-        ipTos = in.readInt();
-        ipTtl = in.readInt();
+    private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException {
+        InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString());
+        InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString());
+        int srcPort = in.readInt();
+        int dstPort = in.readInt();
+        byte[] packet = in.createByteArray();
+        int tcpSeq = in.readInt();
+        int tcpAck = in.readInt();
+        int tcpWnd = in.readInt();
+        int tcpWndScale = in.readInt();
+        int ipTos = in.readInt();
+        int ipTtl = in.readInt();
+        return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq,
+                tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl);
     }
 
     /** Parcelable Creator. */
     public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
             new Parcelable.Creator<TcpKeepalivePacketData>() {
                 public TcpKeepalivePacketData createFromParcel(Parcel in) {
-                    return new TcpKeepalivePacketData(in);
+                    try {
+                        return readFromParcel(in);
+                    } catch (InvalidPacketException e) {
+                        throw new IllegalArgumentException(
+                                "Invalid NAT-T keepalive data: " + e.error);
+                    }
                 }
 
                 public TcpKeepalivePacketData[] newArray(int size) {
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index a3618b4..b329aee 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -22,7 +22,7 @@
 import android.net.DhcpResultsParcelable;
 import android.net.Layer2PacketParcelable;
 import android.net.LinkProperties;
-import android.net.NetworkStackClient;
+import android.net.networkstack.ModuleNetworkStackClient;
 import android.os.ConditionVariable;
 
 import java.io.FileDescriptor;
@@ -75,11 +75,11 @@
      *
      * <p>This is a convenience method to allow clients to use {@link IpClientCallbacks} instead of
      * {@link IIpClientCallbacks}.
-     * @see {@link NetworkStackClient#makeIpClient(String, IIpClientCallbacks)}
+     * @see {@link ModuleNetworkStackClient#makeIpClient(String, IIpClientCallbacks)}
      */
     public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) {
-        // TODO: migrate clients and remove context argument
-        NetworkStackClient.getInstance().makeIpClient(ifName, new IpClientCallbacksProxy(callback));
+        ModuleNetworkStackClient.getInstance(context)
+                .makeIpClient(ifName, new IpClientCallbacksProxy(callback));
     }
 
     /**
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
index 602e4e1..25ab5d3 100644
--- a/services/robotests/Android.bp
+++ b/services/robotests/Android.bp
@@ -27,7 +27,7 @@
         "services.net",
     ],
 
-    libs: ["ike-stubs"],
+    libs: ["android.net.ipsec.ike.stubs.system"],
 }
 
 //##################################################################
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index 5160eae..32587ac 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -29,7 +29,7 @@
         "services.net",
     ],
 
-    libs: ["ike-stubs"],
+    libs: ["android.net.ipsec.ike.stubs.system"],
 }
 
 //##################################################################
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index c94bb87..5c82200 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -79,6 +79,7 @@
     private static final String CALLING_PACKAGE2 = "com.package.name2";
     private static final String NAMESPACE1 = "namespace1";
     private static final String NAMESPACE2 = "namespace2";
+    private static final String DISABLE_RESCUE_PARTY_FLAG = "disable_rescue_party";
 
     private MockitoSession mSession;
     private HashMap<String, String> mSystemSettingsMap;
@@ -316,6 +317,13 @@
 
     @Test
     public void testExplicitlyEnablingAndDisablingRescue() {
+        // mock the DeviceConfig get call to avoid hitting
+        // android.permission.READ_DEVICE_CONFIG when calling real DeviceConfig.
+        doReturn(true)
+                .when(() -> DeviceConfig.getBoolean(
+                    eq(DeviceConfig.NAMESPACE_CONFIGURATION),
+                    eq(DISABLE_RESCUE_PARTY_FLAG),
+                    eq(false)));
         SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
         SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
         assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
@@ -327,6 +335,22 @@
     }
 
     @Test
+    public void testDisablingRescueByDeviceConfigFlag() {
+        doReturn(true)
+                .when(() -> DeviceConfig.getBoolean(
+                    eq(DeviceConfig.NAMESPACE_CONFIGURATION),
+                    eq(DISABLE_RESCUE_PARTY_FLAG),
+                    eq(false)));
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
+
+        assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
+                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
+
+        // Restore the property value initalized in SetUp()
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+    }
+
+    @Test
     public void testHealthCheckLevels() {
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
 
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 c45ee7b..efe8119 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -127,11 +127,14 @@
         mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal());
         mAms.mPackageManagerInt = mPackageManagerInt;
         doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+        // Remove stale instance of PackageManagerInternal if there is any
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
     }
 
     @After
     public void tearDown() {
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
         mHandlerThread.quit();
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index fe42dc9..7a175ca1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -94,6 +94,7 @@
 import com.android.server.wm.ActivityTaskManagerService;
 import com.android.server.wm.WindowProcessController;
 
+import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -141,6 +142,8 @@
         sPackageManagerInternal = mock(PackageManagerInternal.class);
         doReturn(new ComponentName("", "")).when(sPackageManagerInternal)
                 .getSystemUiServiceComponent();
+        // Remove stale instance of PackageManagerInternal if there is any
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal);
 
         sService = mock(ActivityManagerService.class);
@@ -151,6 +154,8 @@
 
         sService.mConstants = new ActivityManagerConstants(sContext, sService,
                 sContext.getMainThreadHandler());
+        setFieldValue(ActivityManagerService.class, sService, "mContext",
+                sContext);
         ProcessList pr = new ProcessList();
         pr.init(sService, new ActiveUids(sService, false), null);
         setFieldValue(ActivityManagerService.class, sService, "mProcessList",
@@ -170,6 +175,11 @@
         sService.mOomAdjuster.mAdjSeq = 10000;
     }
 
+    @AfterClass
+    public static void tearDownOnce() {
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+    }
+
     private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
         try {
             Field field = clazz.getDeclaredField(fieldName);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 959dc05..de6f55b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -147,7 +147,7 @@
         AndroidPackage mockMyPkg = mock(AndroidPackage.class);
         when(mockMyPkg.isPrivileged()).thenReturn(false);
         when(mockMyPkg.getUid()).thenReturn(mMyUid);
-        when(mockMyPkg.getFeatures()).thenReturn(Collections.emptyList());
+        when(mockMyPkg.getAttributions()).thenReturn(Collections.emptyList());
 
         when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg);
         doReturn(mockPackageManagerInternal).when(
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 164ee31..3ad9054 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -182,7 +182,8 @@
                 eq(0),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
     }
 
     @Test
@@ -264,7 +265,8 @@
                 eq(BiometricAuthenticator.TYPE_FACE),
                 eq(false) /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
     }
 
     @Test
@@ -391,7 +393,8 @@
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
 
         // Hardware authenticated
         mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
@@ -406,7 +409,8 @@
 
         // SystemUI sends callback with dismissed reason
         mBiometricService.mInternalReceiver.onDialogDismissed(
-                BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED);
+                BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
+                null /* credentialAttestation */);
         waitForIdle();
         // HAT sent to keystore
         verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
@@ -438,7 +442,8 @@
                 eq(0 /* biometricModality */),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
     }
 
     @Test
@@ -460,7 +465,8 @@
 
         // SystemUI sends confirm, HAT is sent to keystore and client is notified.
         mBiometricService.mInternalReceiver.onDialogDismissed(
-                BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED);
+                BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
+                null /* credentialAttestation */);
         waitForIdle();
         verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
         verify(mReceiver1).onAuthenticationSucceeded(
@@ -567,7 +573,8 @@
                 anyInt(),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                anyString());
+                anyString(),
+                anyLong() /* sessionId */);
     }
 
     @Test
@@ -627,8 +634,8 @@
         verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
 
         // SystemUI animation completed, client is notified, auth session is over
-        mBiometricService.mInternalReceiver
-                .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_ERROR, null /* credentialAttestation */);
         waitForIdle();
         verify(mReceiver1).onError(
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -667,7 +674,8 @@
                 eq(0 /* biometricModality */),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
     }
 
     @Test
@@ -825,8 +833,8 @@
         invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                 false /* requireConfirmation */, null /* authenticators */);
 
-        mBiometricService.mInternalReceiver
-                .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+        mBiometricService.mInternalReceiver.onDialogDismissed(
+                BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
         waitForIdle();
         verify(mReceiver1).onError(
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -854,7 +862,7 @@
                 BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
                 0 /* vendorCode */);
         mBiometricService.mInternalReceiver.onDialogDismissed(
-                BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+                BiometricPrompt.DISMISSED_REASON_NEGATIVE, null /* credentialAttestation */);
         waitForIdle();
 
         verify(mBiometricService.mAuthenticators.get(0).impl,
@@ -880,7 +888,7 @@
                 BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
                 0 /* vendorCode */);
         mBiometricService.mInternalReceiver.onDialogDismissed(
-                BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
         waitForIdle();
 
         verify(mBiometricService.mAuthenticators.get(0).impl,
@@ -903,7 +911,7 @@
                 true /* requireConfirmation */,
                 new byte[69] /* HAT */);
         mBiometricService.mInternalReceiver.onDialogDismissed(
-                BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
         waitForIdle();
 
         // doesn't send cancel to HAL
@@ -1160,7 +1168,8 @@
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
 
         // Requesting strong and credential, when credential is setup
         resetReceiver();
@@ -1179,7 +1188,8 @@
                 eq(BiometricAuthenticator.TYPE_NONE /* biometricModality */),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
 
         // Un-downgrading the authenticator allows successful strong auth
         for (BiometricService.AuthenticatorWrapper wrapper : mBiometricService.mAuthenticators) {
@@ -1201,7 +1211,8 @@
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */),
                 anyBoolean() /* requireConfirmation */,
                 anyInt() /* userId */,
-                eq(TEST_PACKAGE_NAME));
+                eq(TEST_PACKAGE_NAME),
+                anyLong() /* sessionId */);
     }
 
     @Test(expected = IllegalStateException.class)
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 2944643..8be9213 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -251,6 +251,28 @@
     }
 
     @Test
+    public void testAllowRemoveOverrideNoOverride() throws Exception {
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1234L)
+                .addLoggingOnlyChangeWithId(2L)
+                .build();
+        ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+                .withPackageName("com.some.package")
+                .build();
+        when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+                .thenReturn(applicationInfo);
+
+        // Reject all override attempts.
+        // Force the validator to prevent overriding the change by using a user build.
+        when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+        when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+        // Try to remove a non existing override, and it doesn't fail.
+        assertThat(compatConfig.removeOverride(1234L, "com.some.package")).isFalse();
+        assertThat(compatConfig.removeOverride(2L, "com.some.package")).isFalse();
+        compatConfig.removePackageOverrides("com.some.package");
+    }
+
+    @Test
     public void testRemovePackageOverride() throws Exception {
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addEnabledChangeWithId(1234L)
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 2a6a24e..d038d6c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3872,79 +3872,80 @@
             Settings.System.SCREEN_BRIGHTNESS, "0", DpmMockContext.CALLER_USER_HANDLE);
     }
 
-    public void testSetAutoTimeModifiesSetting() throws Exception {
+    public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
-        dpm.setAutoTime(admin1, true);
+        dpm.setAutoTimeEnabled(admin1, true);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
 
-        dpm.setAutoTime(admin1, false);
+        dpm.setAutoTimeEnabled(admin1, false);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
     }
 
-    public void testSetAutoTimeWithPOOnUser0() throws Exception {
+    public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupProfileOwnerOnUser0();
-        dpm.setAutoTime(admin1, true);
+        dpm.setAutoTimeEnabled(admin1, true);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
 
-        dpm.setAutoTime(admin1, false);
+        dpm.setAutoTimeEnabled(admin1, false);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
     }
 
-    public void testSetAutoTimeFailWithPONotOnUser0() throws Exception {
+    public void testSetAutoTimeEnabledFailWithPONotOnUser0() throws Exception {
         setupProfileOwner();
-        assertExpectException(SecurityException.class, null, () -> dpm.setAutoTime(admin1, false));
+        assertExpectException(SecurityException.class, null,
+                () -> dpm.setAutoTimeEnabled(admin1, false));
         verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
     }
 
-    public void testSetAutoTimeWithPOOfOrganizationOwnedDevice() throws Exception {
+    public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
 
-        dpm.setAutoTime(admin1, true);
+        dpm.setAutoTimeEnabled(admin1, true);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
 
-        dpm.setAutoTime(admin1, false);
+        dpm.setAutoTimeEnabled(admin1, false);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
     }
 
-    public void testSetAutoTimeZoneModifiesSetting() throws Exception {
+    public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
-        dpm.setAutoTimeZone(admin1, true);
+        dpm.setAutoTimeZoneEnabled(admin1, true);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
 
-        dpm.setAutoTimeZone(admin1, false);
+        dpm.setAutoTimeZoneEnabled(admin1, false);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
     }
 
-    public void testSetAutoTimeZoneWithPOOnUser0() throws Exception {
+    public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupProfileOwnerOnUser0();
-        dpm.setAutoTimeZone(admin1, true);
+        dpm.setAutoTimeZoneEnabled(admin1, true);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
 
-        dpm.setAutoTimeZone(admin1, false);
+        dpm.setAutoTimeZoneEnabled(admin1, false);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
     }
 
-    public void testSetAutoTimeZoneFailWithPONotOnUser0() throws Exception {
+    public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
         setupProfileOwner();
         assertExpectException(SecurityException.class, null,
-                () -> dpm.setAutoTimeZone(admin1, false));
+                () -> dpm.setAutoTimeZoneEnabled(admin1, false));
         verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE,
                 0);
     }
 
-    public void testSetAutoTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception {
+    public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
 
-        dpm.setAutoTimeZone(admin1, true);
+        dpm.setAutoTimeZoneEnabled(admin1, true);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
 
-        dpm.setAutoTimeZone(admin1, false);
+        dpm.setAutoTimeZoneEnabled(admin1, false);
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
     }
 
@@ -5842,7 +5843,7 @@
         assertTrue(dpm.isPackageAllowedToAccessCalendar(testPackage));
     }
 
-    public void testSetProtectedPackages_asDO() throws Exception {
+    public void testSetUserControlDisabledPackages_asDO() throws Exception {
         final List<String> testPackages = new ArrayList<>();
         testPackages.add("package_1");
         testPackages.add("package_2");
@@ -5850,14 +5851,14 @@
         mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
         setDeviceOwner();
 
-        dpm.setProtectedPackages(admin1, testPackages);
+        dpm.setUserControlDisabledPackages(admin1, testPackages);
 
         verify(getServices().packageManagerInternal).setDeviceOwnerProtectedPackages(testPackages);
 
-        assertEquals(testPackages, dpm.getProtectedPackages(admin1));
+        assertEquals(testPackages, dpm.getUserControlDisabledPackages(admin1));
     }
 
-    public void testSetProtectedPackages_failingAsPO() throws Exception {
+    public void testSetUserControlDisabledPackages_failingAsPO() throws Exception {
         final List<String> testPackages = new ArrayList<>();
         testPackages.add("package_1");
         testPackages.add("package_2");
@@ -5866,10 +5867,10 @@
         setAsProfileOwner(admin1);
 
         assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.setProtectedPackages(admin1, testPackages));
+                () -> dpm.setUserControlDisabledPackages(admin1, testPackages));
 
         assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.getProtectedPackages(admin1));
+                () -> dpm.getUserControlDisabledPackages(admin1));
     }
 
     private void configureProfileOwnerOfOrgOwnedDevice(ComponentName who, int userId) {
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 3dd1504..d3a3e7e 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -28,6 +28,7 @@
 
 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.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -321,6 +322,11 @@
         // we cannot check installer cert because it seems to be device specific.
         assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
         assertFalse(appInstallMetadata.isPreInstalled());
+        // Asserting source stamp not present.
+        assertFalse(appInstallMetadata.isStampPresent());
+        assertFalse(appInstallMetadata.isStampVerified());
+        assertFalse(appInstallMetadata.isStampTrusted());
+        assertNull(appInstallMetadata.getStampCertificateHash());
         // These are hardcoded in the test apk android manifest
         Map<String, String> allowedInstallers =
                 appInstallMetadata.getAllowedInstallersAndCertificates();
@@ -474,6 +480,13 @@
         assertThat(mService.getCurrentRules().getList()).containsExactly(rule);
     }
 
+    @Test
+    public void getWhitelistedRuleProviders() throws Exception {
+        whitelistUsAsRuleProvider();
+
+        assertThat(mService.getWhitelistedRuleProviders()).containsExactly(TEST_FRAMEWORK_PACKAGE);
+    }
+
     private void whitelistUsAsRuleProvider() {
         Resources mockResources = mock(Resources.class);
         when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 8da3bdf..155c6dd 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -28,6 +28,8 @@
 import android.media.tv.tuner.frontend.FrontendSettings;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
+import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
 import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
@@ -92,6 +94,13 @@
             }
         };
 
+    private static int getResourceIdFromHandle(int resourceHandle) {
+        if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+            return resourceHandle;
+        }
+        return (resourceHandle & 0x00ff0000) >> 16;
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -229,14 +238,15 @@
     public void requestFrontendTest_ClientNotRegistered() {
         TunerFrontendRequest request =
                 new TunerFrontendRequest(0 /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isFalse();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isFalse();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(TunerResourceManager.INVALID_FRONTEND_ID);
+        assertThat(getResourceIdFromHandle(frontendHandle[0]))
+                .isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
     }
 
     @Test
@@ -256,14 +266,15 @@
 
         TunerFrontendRequest request =
                 new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isFalse();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isFalse();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(TunerResourceManager.INVALID_FRONTEND_ID);
+        assertThat(getResourceIdFromHandle(frontendHandle[0]))
+                .isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
     }
 
     @Test
@@ -287,14 +298,14 @@
 
         TunerFrontendRequest request =
                 new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(0);
+        assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(0);
     }
 
     @Test
@@ -322,26 +333,26 @@
                 new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
         mTunerResourceManagerService.setFrontendInfoListInternal(infos);
 
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         TunerFrontendRequest request =
                 new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(infos[0].getId());
+        assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[0].getId());
 
         request =
                 new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(infos[1].getId());
+        assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[1].getId());
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
                 .isInUse()).isTrue();
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[2].getId())
@@ -382,10 +393,10 @@
 
         TunerFrontendRequest request =
                 new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -393,8 +404,8 @@
         request =
                 new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isFalse();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isFalse();
             assertThat(listener.isRelaimed()).isFalse();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -403,8 +414,8 @@
         request =
                 new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isFalse();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isFalse();
             assertThat(listener.isRelaimed()).isFalse();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -444,24 +455,24 @@
 
         TunerFrontendRequest request =
                 new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(infos[0].getId());
+        assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[0].getId());
 
         request =
                 new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(infos[1].getId());
+        assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[1].getId());
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
                 .isInUse()).isTrue();
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
@@ -493,14 +504,14 @@
 
         TunerFrontendRequest request =
                 new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
-        int[] frontendId = new int[1];
+        int[] frontendHandle = new int[1];
         try {
-            assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
-                    .isTrue();
+            assertThat(mTunerResourceManagerService
+                    .requestFrontendInternal(request, frontendHandle)).isTrue();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        assertThat(frontendId[0]).isEqualTo(infos[0].getId());
+        assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[0].getId());
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
                 .isInUse()).isTrue();
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
@@ -515,4 +526,38 @@
         assertThat(mTunerResourceManagerService.checkClientExists(clientId[0])).isFalse();
 
     }
+
+    @Test
+    public void requestDemuxTest() {
+        // Register client
+        ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/,
+                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+        int[] clientId = new int[1];
+        mTunerResourceManagerService.registerClientProfileInternal(
+                profile, null /*listener*/, clientId);
+        assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+
+        int[] demuxHandle = new int[1];
+        TunerDemuxRequest request = new TunerDemuxRequest(clientId[0]);
+        assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle))
+                .isTrue();
+        assertThat(getResourceIdFromHandle(demuxHandle[0])).isEqualTo(0);
+    }
+
+    @Test
+    public void requestDescramblerTest() {
+        // Register client
+        ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/,
+                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+        int[] clientId = new int[1];
+        mTunerResourceManagerService.registerClientProfileInternal(
+                profile, null /*listener*/, clientId);
+        assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+
+        int[] desHandle = new int[1];
+        TunerDescramblerRequest request = new TunerDescramblerRequest(clientId[0]);
+        assertThat(mTunerResourceManagerService.requestDescramblerInternal(request, desHandle))
+                .isTrue();
+        assertThat(getResourceIdFromHandle(desHandle[0])).isEqualTo(0);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 64d481a..6c81930 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -41,8 +41,6 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -462,6 +460,15 @@
     }
 
     @After
+    public void assertNotificationRecordLoggerCallsValid() {
+        for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) {
+            if (call.wasLogged) {
+                assertNotNull(call.event);
+            }
+        }
+    }
+
+    @After
     public void tearDown() throws Exception {
         if (mFile != null) mFile.delete();
         clearDeviceConfig();
@@ -1150,10 +1157,10 @@
         mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0,
                 generateNotificationRecord(null).getNotification(), 0);
         waitForIdle();
-        assertEquals(1, mNotificationRecordLogger.getCalls().size());
+        assertEquals(1, mNotificationRecordLogger.numCalls());
 
         NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0);
-        assertTrue(call.shouldLogReported);
+        assertTrue(call.wasLogged);
         assertEquals(NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
                 call.event);
         assertNotNull(call.r);
@@ -1179,18 +1186,18 @@
                 .setCategory(Notification.CATEGORY_ALARM).build();
         mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, update, 0);
         waitForIdle();
-        assertEquals(2, mNotificationRecordLogger.getCalls().size());
+        assertEquals(2, mNotificationRecordLogger.numCalls());
 
-        assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
+        assertTrue(mNotificationRecordLogger.get(0).wasLogged);
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
-                mNotificationRecordLogger.get(0).event);
+                mNotificationRecordLogger.event(0));
         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
 
-        assertTrue(mNotificationRecordLogger.get(1).shouldLogReported);
+        assertTrue(mNotificationRecordLogger.get(1).wasLogged);
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED,
-                mNotificationRecordLogger.get(1).event);
+                mNotificationRecordLogger.event(1));
         // Instance ID doesn't change on update of an active notification
         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
     }
@@ -1203,13 +1210,13 @@
         mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0,
                 generateNotificationRecord(null).getNotification(), 0);
         waitForIdle();
-        assertEquals(2, mNotificationRecordLogger.getCalls().size());
-        assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertTrue(mNotificationRecordLogger.get(0).wasLogged);
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
-                mNotificationRecordLogger.get(0).event);
-        assertFalse(mNotificationRecordLogger.get(1).shouldLogReported);
-        assertNull(mNotificationRecordLogger.get(1).event);
+                mNotificationRecordLogger.event(0));
+        assertFalse(mNotificationRecordLogger.get(1).wasLogged);
+        assertNull(mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -1222,11 +1229,11 @@
         notif.extras.putString(Notification.EXTRA_TITLE, "Changed title");
         mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, notif, 0);
         waitForIdle();
-        assertEquals(2, mNotificationRecordLogger.getCalls().size());
+        assertEquals(2, mNotificationRecordLogger.numCalls());
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
-                mNotificationRecordLogger.get(0).event);
-        assertNull(mNotificationRecordLogger.get(1).event);
+                mNotificationRecordLogger.event(0));
+        assertNull(mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -1241,23 +1248,23 @@
         waitForIdle();
         mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, notification, 0);
         waitForIdle();
-        assertEquals(3, mNotificationRecordLogger.getCalls().size());
+        assertEquals(3, mNotificationRecordLogger.numCalls());
 
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
-                mNotificationRecordLogger.get(0).event);
-        assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
+                mNotificationRecordLogger.event(0));
+        assertTrue(mNotificationRecordLogger.get(0).wasLogged);
         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
 
         assertEquals(
                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
-                mNotificationRecordLogger.get(1).event);
+                mNotificationRecordLogger.event(1));
         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
 
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
-                mNotificationRecordLogger.get(2).event);
-        assertTrue(mNotificationRecordLogger.get(2).shouldLogReported);
+                mNotificationRecordLogger.event(2));
+        assertTrue(mNotificationRecordLogger.get(2).wasLogged);
         // New instance ID because notification was canceled before re-post
         assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId());
     }
@@ -1269,7 +1276,7 @@
         waitForIdle();
         // The notification record logger doesn't even get called when a nonexistent notification
         // is cancelled, because that happens very frequently and is not interesting.
-        assertEquals(0, mNotificationRecordLogger.getCalls().size());
+        assertEquals(0, mNotificationRecordLogger.numCalls());
     }
 
     @Test
@@ -2527,6 +2534,13 @@
         // only snooze the one notification
         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
         assertTrue(nonGrouped.getStats().hasSnoozed());
+
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
+                mNotificationRecordLogger.event(0));
+        assertEquals(
+                NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
+                mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -2569,6 +2583,12 @@
 
         // only snooze the one child
         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
+
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
+                mNotificationRecordLogger.event(0));
+        assertEquals(NotificationRecordLogger.NotificationCancelledEvent
+                        .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -2588,6 +2608,18 @@
 
         // snooze child and summary
         verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
+
+        assertEquals(4, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
+                mNotificationRecordLogger.event(0));
+        assertEquals(
+                NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
+                mNotificationRecordLogger.event(1));
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
+                mNotificationRecordLogger.event(2));
+        assertEquals(
+                NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
+                mNotificationRecordLogger.event(3));
     }
 
     @Test
@@ -2603,6 +2635,13 @@
 
         // snooze child only
         verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
+
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED,
+                mNotificationRecordLogger.event(0));
+        assertEquals(
+                NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED,
+                mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -3386,6 +3425,10 @@
         mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied());
         verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r.getSbn()));
+
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
+                mNotificationRecordLogger.event(0));
     }
 
     @Test
@@ -3404,6 +3447,12 @@
         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), eq(true),
                 eq((false)));
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
+
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER,
+                mNotificationRecordLogger.event(0));
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER,
+                mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -3465,11 +3514,11 @@
 
         // Using mService.addNotification() does not generate a NotificationRecordLogger log,
         // so we only get the cancel notification.
-        assertEquals(1, mNotificationRecordLogger.getCalls().size());
+        assertEquals(1, mNotificationRecordLogger.numCalls());
 
         assertEquals(
                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
-                mNotificationRecordLogger.get(0).event);
+                mNotificationRecordLogger.event(0));
         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
     }
 
@@ -4351,9 +4400,9 @@
                 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
                 new NotificationVisibility[]{});
 
-        assertEquals(1, mNotificationRecordLogger.getCalls().size());
+        assertEquals(1, mNotificationRecordLogger.numCalls());
         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN,
-                mNotificationRecordLogger.get(0).event);
+                mNotificationRecordLogger.event(0));
         assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
 
         mService.mNotificationDelegate.onNotificationVisibilityChanged(
@@ -4362,9 +4411,9 @@
                         {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}
         );
 
-        assertEquals(2, mNotificationRecordLogger.getCalls().size());
+        assertEquals(2, mNotificationRecordLogger.numCalls());
         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE,
-                mNotificationRecordLogger.get(1).event);
+                mNotificationRecordLogger.event(1));
         assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
     }
 
@@ -4788,6 +4837,12 @@
 
         mService.mNotificationDelegate.onPanelHidden();
         verify(mAssistants, times(1)).onPanelHidden();
+
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN,
+                mNotificationRecordLogger.event(0));
+        assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE,
+                mNotificationRecordLogger.event(1));
     }
 
     @Test
@@ -4806,6 +4861,9 @@
                 modifiedBeforeSending);
         verify(mAssistants).notifyAssistantSuggestedReplySent(
                 eq(r.getSbn()), eq(reply), eq(generatedByAssistant));
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
+                mNotificationRecordLogger.event(0));
     }
 
     @Test
@@ -4825,6 +4883,10 @@
                 generatedByAssistant);
         verify(mAssistants).notifyAssistantActionClicked(
                 eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
+
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED,
+                mNotificationRecordLogger.event(0));
     }
 
     @Test
@@ -5489,6 +5551,10 @@
         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
         assertEquals(1, notifs.length);
         assertEquals(1, mService.getNotificationRecordCount());
+
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationCancelledEvent
+                .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
     }
 
     @Test
@@ -6168,6 +6234,17 @@
         // The bubble should still exist
         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
         assertEquals(1, notifsAfter.length);
+
+        // Check we got the click log and associated dismissal logs
+        assertEquals(6, mNotificationRecordLogger.numCalls());
+        // Skip the notification-creation logs
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
+                mNotificationRecordLogger.event(3));
+        assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK,
+                mNotificationRecordLogger.event(4));
+        assertEquals(NotificationRecordLogger.NotificationCancelledEvent
+                        .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED,
+                mNotificationRecordLogger.event(5));
     }
 
     @Test
@@ -6188,6 +6265,11 @@
         // THEN the bubble should still exist
         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
         assertEquals(1, notifsAfter.length);
+
+        // Check we got the click log
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED,
+                mNotificationRecordLogger.event(0));
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
index 2a17bae..6b18cc6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
@@ -31,25 +31,29 @@
         // The following fields are only relevant to maybeLogNotificationPosted() calls.
         static final int INVALID = -1;
         public int position = INVALID, buzzBeepBlink = INVALID;
-        public boolean shouldLogReported;
+        public boolean wasLogged;
 
         CallRecord(NotificationRecord r, NotificationRecord old, int position,
                 int buzzBeepBlink) {
             super(r, old);
             this.position = position;
             this.buzzBeepBlink = buzzBeepBlink;
-            shouldLogReported = shouldLogReported(buzzBeepBlink);
-            event = shouldLogReported ? NotificationReportedEvent.fromRecordPair(this) : null;
+            wasLogged = shouldLogReported(buzzBeepBlink);
+            event = wasLogged ? NotificationReportedEvent.fromRecordPair(this) : null;
         }
 
         CallRecord(NotificationRecord r, UiEventLogger.UiEventEnum event) {
             super(r, null);
-            shouldLogReported = false;
+            wasLogged = true;
             this.event = event;
         }
     }
     private List<CallRecord> mCalls = new ArrayList<>();
 
+    public int numCalls() {
+        return mCalls.size();
+    }
+
     List<CallRecord> getCalls() {
         return mCalls;
     }
@@ -57,6 +61,9 @@
     CallRecord get(int index) {
         return mCalls.get(index);
     }
+    UiEventLogger.UiEventEnum event(int index) {
+        return mCalls.get(index).event;
+    }
 
     @Override
     public void maybeLogNotificationPosted(NotificationRecord r, NotificationRecord old,
@@ -65,13 +72,12 @@
     }
 
     @Override
-    public void logNotificationCancelled(NotificationRecord r, int reason, int dismissalSurface) {
-        mCalls.add(new CallRecord(r,
-                NotificationCancelledEvent.fromCancelReason(reason, dismissalSurface)));
+    public void log(UiEventLogger.UiEventEnum event, NotificationRecord r) {
+        mCalls.add(new CallRecord(r, event));
     }
 
     @Override
-    public void logNotificationVisibility(NotificationRecord r, boolean visible) {
-        mCalls.add(new CallRecord(r, NotificationEvent.fromVisibility(visible)));
+    public void log(UiEventLogger.UiEventEnum event) {
+        mCalls.add(new CallRecord(null, event));
     }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java
index 551e186..5a527a2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java
@@ -3,8 +3,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 
+import android.app.Application;
 import android.content.Intent;
 import android.net.Uri;
 import android.service.notification.Condition;
@@ -45,7 +47,7 @@
                 null,               // ActivityThread not actually used in Service
                 ScheduleConditionProvider.class.getName(),
                 null,               // token not needed when not talking with the activity manager
-                null,
+                mock(Application.class),
                 null                // mocked services don't talk with the activity manager
                 );
         service.onCreate();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index c9c3649..9e87421 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1332,6 +1332,40 @@
         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
     }
 
+    @Test
+    public void testActivityDestroyDoesntChangeProcessOverride() {
+        final ActivityRecord firstActivity =
+                createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+        final WindowProcessController wpc = firstActivity.app;
+        assertTrue(wpc.registeredForActivityConfigChanges());
+        assertEquals(0, firstActivity.getMergedOverrideConfiguration()
+                .diff(wpc.getRequestedOverrideConfiguration()));
+
+        final ActivityRecord secondActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, wpc);
+        assertTrue(wpc.registeredForActivityConfigChanges());
+        assertEquals(0, secondActivity.getMergedOverrideConfiguration()
+                .diff(wpc.getRequestedOverrideConfiguration()));
+
+        final ActivityRecord thirdActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, wpc);
+        assertTrue(wpc.registeredForActivityConfigChanges());
+        assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
+                .diff(wpc.getRequestedOverrideConfiguration()));
+
+        secondActivity.destroyImmediately(true, "");
+
+        assertTrue(wpc.registeredForActivityConfigChanges());
+        assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
+                .diff(wpc.getRequestedOverrideConfiguration()));
+
+        firstActivity.destroyImmediately(true, "");
+
+        assertTrue(wpc.registeredForActivityConfigChanges());
+        assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
+                .diff(wpc.getRequestedOverrideConfiguration()));
+    }
+
     /**
      * Creates an activity on display. For non-default display request it will also create a new
      * display with custom DisplayInfo.
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 12d89de..8f3ff52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -37,8 +37,8 @@
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.server.LocalServices;
 import com.android.server.pm.PackageList;
@@ -72,6 +72,10 @@
             ComponentName.createRelative("com.android.foo", ".BarActivity");
     private static final ComponentName ALTERNATIVE_COMPONENT =
             ComponentName.createRelative("com.android.foo", ".AlternativeBarActivity");
+    private static final String TEST_WINDOW_LAYOUT_AFFINITY = "135:.Affinity";
+    private static final String TEST_ALTERNATIVE_WINDOW_LAYOUT_AFFINITY =
+            "246:.AlternativeAffinity";
+    private static final String TEST_DIFFERENT_AFFINITY_WITH_SAME_UID = "135:.DifferentAffinity";
 
     private static final int TEST_WINDOWING_MODE = WINDOWING_MODE_FREEFORM;
     private static final Rect TEST_BOUNDS = new Rect(100, 200, 300, 400);
@@ -99,11 +103,12 @@
     public void setUp() throws Exception {
         mPersisterQueue = new TestPersisterQueue();
 
-        final File cacheFolder = InstrumentationRegistry.getContext().getCacheDir();
+        final File cacheFolder =
+                InstrumentationRegistry.getInstrumentation().getContext().getCacheDir();
         mFolder = new File(cacheFolder, "launch_params_tests");
         deleteRecursively(mFolder);
 
-        mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
+        mDisplayUniqueId = "test:" + sNextUniqueId++;
         mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
                 .setUniqueId(mDisplayUniqueId).build();
         when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
@@ -211,6 +216,61 @@
     }
 
     @Test
+    public void testUsesRecordWithSameWindowLayoutAffinityInSameInstance_NoPreviousRecord() {
+        mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTestTask);
+
+        mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+        assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+        assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+        assertEquals(TEST_BOUNDS, mResult.mBounds);
+    }
+
+    @Test
+    public void testUsesRecordWithSameWindowLayoutAffinityInSameInstance_HasOldPreviousRecord()
+            throws Exception {
+        mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTaskWithDifferentComponent);
+
+        Thread.sleep(1);  // Sleep 1ms so that the timestamp can for sure increase.
+
+        mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTestTask);
+
+        mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+        assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+        assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+        assertEquals(TEST_BOUNDS, mResult.mBounds);
+    }
+
+    @Test
+    public void testReturnsEmptyLaunchParamsUidInLaunchAffinityMismatch() {
+        mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTestTask);
+
+        mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_DIFFERENT_AFFINITY_WITH_SAME_UID;
+        mResult.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+        mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+        assertTrue("Result must be empty.", mResult.isEmpty());
+    }
+
+    @Test
+    public void testReturnsEmptyLaunchParamsWindowLayoutAffinityMismatch() {
+        mTestTask.affinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTestTask);
+
+        mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_ALTERNATIVE_WINDOW_LAYOUT_AFFINITY;
+        mResult.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+        mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+        assertTrue("Result must be empty.", mResult.isEmpty());
+    }
+
+    @Test
     public void testSavesAndRestoresLaunchParamsAcrossInstances() {
         mTarget.saveTask(mTestTask);
         mPersisterQueue.flush();
@@ -228,6 +288,52 @@
     }
 
     @Test
+    public void testUsesRecordWithSameWindowLayoutAffinityAcrossInstances_NoPreviousRecord() {
+        mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTestTask);
+        mPersisterQueue.flush();
+
+        final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
+                mUserFolderGetter);
+        target.onSystemReady();
+        target.onUnlockUser(TEST_USER_ID);
+
+        mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        target.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+        assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+        assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+        assertEquals(TEST_BOUNDS, mResult.mBounds);
+    }
+
+    @Test
+    public void testUsesRecordWithSameWindowLayoutAffinityAcrossInstances_HasOldPreviousRecord()
+            throws Exception {
+        mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTaskWithDifferentComponent);
+        mPersisterQueue.flush();
+
+        // Sleep 1s because many file systems only save last modified time as precise as 1s so we
+        // can for sure know the last modified time is different.
+        Thread.sleep(1000);
+
+        mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+        mTarget.saveTask(mTestTask);
+        mPersisterQueue.flush();
+
+        final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
+                mUserFolderGetter);
+        target.onSystemReady();
+        target.onUnlockUser(TEST_USER_ID);
+
+        target.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+        assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+        assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+        assertEquals(TEST_BOUNDS, mResult.mBounds);
+    }
+
+    @Test
     public void testClearsRecordsOfTheUserOnUserCleanUp() {
         mTarget.saveTask(mTestTask);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 277bc41..67b1dac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -27,6 +27,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -109,5 +111,27 @@
         assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
                 mWm.getDefaultDisplayContentLocked().getWindowingMode());
     }
+
+    /**
+     * This test ensures that an existing single instance activity with alias name can be found by
+     * the same activity info. So {@link ActivityStarter#getReusableTask} won't miss it that leads
+     * to create an unexpected new instance.
+     */
+    @Test
+    public void testFindActivityByTargetComponent() {
+        final ComponentName aliasComponent = ComponentName.createRelative(
+                ActivityTestsBase.DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity");
+        final ComponentName targetComponent = ComponentName.createRelative(
+                aliasComponent.getPackageName(), ".TargetActivity");
+        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+                .setComponent(aliasComponent)
+                .setTargetActivity(targetComponent.getClassName())
+                .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
+                .setCreateTask(true)
+                .build();
+
+        assertEquals(activity, mWm.mRoot.findActivity(activity.intent, activity.info,
+                false /* compareIntentFilters */));
+    }
 }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index ba4a82f..edf81ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -107,10 +107,16 @@
         setUpApp(display);
 
         // Put app window into freeform and then make it a compat app.
-        mTask.setBounds(100, 100, 400, 600);
+        final Rect bounds = new Rect(100, 100, 400, 600);
+        mTask.setBounds(bounds);
         prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(bounds, mActivity.getBounds());
 
-        final Rect bounds = new Rect(mActivity.getBounds());
+        // The activity should be able to accept negative x position [-150, 100 - 150, 600].
+        final int dx = bounds.left + bounds.width() / 2;
+        mTask.setBounds(bounds.left - dx, bounds.top, bounds.right - dx, bounds.bottom);
+        assertEquals(mTask.getBounds(), mActivity.getBounds());
+
         final int density = mActivity.getConfiguration().densityDpi;
 
         // change display configuration to fullscreen
@@ -231,11 +237,7 @@
         // The position should be horizontal centered.
         assertEquals((displayWidth - bounds.width()) / 2, bounds.left);
 
-        final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
-                mService.mWindowManager, mock(Session.class), new TestIWindow(),
-                new WindowManager.LayoutParams(), mActivity);
-        mActivity.addWindow(w);
-        mActivity.mDisplayContent.mInputMethodTarget = w;
+        mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity);
         // Make sure IME cannot attach to the app, otherwise IME window will also be shifted.
         assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
     }
@@ -475,6 +477,25 @@
         assertEquals((int) (dw * maxAspect), mActivity.getBounds().width());
         // The bounds should be horizontal centered: (2500-1900)/2=350.
         assertEquals((dh - mActivity.getBounds().width()) / 2, mActivity.getBounds().left);
+
+        // The letterbox needs a main window to layout.
+        addWindowToActivity(mActivity);
+        // Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}.
+        mActivity.mRootWindowContainer.performSurfacePlacement(false /* recoveringMemory */);
+        // The letterbox insets should be [350, 0 - 350, 0].
+        assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0),
+                mActivity.getLetterboxInsets());
+    }
+
+    private WindowState addWindowToActivity(ActivityRecord activity) {
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+        params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+        final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
+                mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+        WindowTestsBase.makeWindowVisible(w);
+        w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+        mActivity.addWindow(w);
+        return w;
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 560d03f..091f493 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -322,6 +322,8 @@
     }
 
     private void tearDown() {
+        mWmService.mRoot.forAllDisplayPolicies(DisplayPolicy::release);
+
         // Unregister display listener from root to avoid issues with subsequent tests.
         mContext.getSystemService(DisplayManager.class)
                 .unregisterDisplayListener(mAtmService.mRootWindowContainer);
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 251886a..5007e3a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -32,6 +32,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -213,6 +214,16 @@
     }
 
     @Test
+    public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        stack.setWindowingMode(WINDOWING_MODE_PINNED);
+
+        final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
+        verify(organizer, times(1)).taskAppeared(any());
+    }
+
+    @Test
     public void testTaskTransaction() {
         removeGlobalMinSizeRestriction();
         final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
@@ -557,6 +568,38 @@
             .transactionReady(anyInt(), any());
     }
 
+    @Test
+    public void testBLASTCallbackWithChildWindow() {
+        final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stackController1, 0 /* userId */);
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window");
+        final WindowState child = createWindow(w, TYPE_APPLICATION, "Other Window");
+
+        w.mActivityRecord.setVisible(true);
+        makeWindowVisible(w, child);
+
+        BLASTSyncEngine bse = new BLASTSyncEngine();
+
+        BLASTSyncEngine.TransactionReadyListener transactionListener =
+            mock(BLASTSyncEngine.TransactionReadyListener.class);
+
+        int id = bse.startSyncSet(transactionListener);
+        assertEquals(true, bse.addToSyncSet(id, task));
+        bse.setReady(id);
+        w.finishDrawing(null);
+
+        // Since we have a child window we still shouldn't be done.
+        verify(transactionListener, never())
+            .transactionReady(anyInt(), any());
+        reset(transactionListener);
+
+        child.finishDrawing(null);
+        // Ah finally! Done
+        verify(transactionListener)
+                .transactionReady(anyInt(), any());
+    }
+
     class StubOrganizer extends ITaskOrganizer.Stub {
         RunningTaskInfo mInfo;
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index ef9a73b..9d48955 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -98,8 +98,7 @@
 
     // Persist versioned backup files.
     // Should be false, except when testing new versions
-    // STOPSHIP: b/139937606 this should be false on launch
-    static final boolean KEEP_BACKUP_DIR = true;
+    static final boolean KEEP_BACKUP_DIR = false;
 
     private static final String TAG = "UsageStatsDatabase";
     private static final boolean DEBUG = UsageStatsService.DEBUG;
@@ -412,6 +411,7 @@
         }
 
         if (mBackupsDir.exists() && !KEEP_BACKUP_DIR) {
+            mUpgradePerformed = true; // updated here to ensure that data is cleaned up
             deleteDirectory(mBackupsDir);
         }
     }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 0d1b352..bbe9851 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -137,8 +137,7 @@
     private static final File USAGE_STATS_LEGACY_DIR = new File(
             Environment.getDataSystemDirectory(), "usagestats");
     // For migration purposes, indicates whether to keep the legacy usage stats directory or not
-    // STOPSHIP: b/138323140 this should be false on launch
-    private static final boolean KEEP_LEGACY_DIR = true;
+    private static final boolean KEEP_LEGACY_DIR = false;
 
     private static final char TOKEN_DELIMITER = '/';
 
@@ -648,7 +647,7 @@
 
     private void deleteLegacyDir(int userId) {
         final File legacyUserDir = new File(USAGE_STATS_LEGACY_DIR, Integer.toString(userId));
-        if (!KEEP_LEGACY_DIR) {
+        if (!KEEP_LEGACY_DIR && legacyUserDir.exists()) {
             deleteRecursively(legacyUserDir);
             if (legacyUserDir.exists()) {
                 Slog.w(TAG, "Error occurred while attempting to delete legacy usage stats "
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 2761127..1792256 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -937,8 +937,8 @@
      */
     public TelecomManager(Context context, ITelecomService telecomServiceImpl) {
         Context appContext = context.getApplicationContext();
-        if (appContext != null && Objects.equals(context.getFeatureId(),
-                appContext.getFeatureId())) {
+        if (appContext != null && Objects.equals(context.getAttributionTag(),
+                appContext.getAttributionTag())) {
             mContext = appContext;
         } else {
             mContext = context;
@@ -972,7 +972,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getDefaultOutgoingPhoneAccount(uriScheme,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getDefaultOutgoingPhoneAccount", e);
@@ -1170,7 +1170,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getSelfManagedPhoneAccounts(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getSelfManagedPhoneAccounts()", e);
@@ -1196,7 +1196,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getCallCapablePhoneAccounts(includeDisabledAccounts,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
@@ -1500,7 +1500,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().isVoiceMailNumber(accountHandle, number,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#isVoiceMailNumber.", e);
@@ -1522,7 +1522,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getVoiceMailNumber(accountHandle,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
@@ -1543,7 +1543,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getLine1Number(accountHandle,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#getLine1Number.", e);
@@ -1565,7 +1565,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().isInCall(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling isInCall().", e);
@@ -1591,7 +1591,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().isInManagedCall(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling isInManagedCall().", e);
@@ -1772,7 +1772,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().isTtySupported(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get TTY supported state.", e);
@@ -1797,7 +1797,7 @@
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getCurrentTtyMode(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get the current TTY mode.", e);
@@ -2027,7 +2027,7 @@
         if (service != null) {
             try {
                 service.showInCallScreen(showDialpad, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
             }
@@ -2090,7 +2090,7 @@
             }
             try {
                 service.placeCall(address, extras == null ? new Bundle() : extras,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#placeCall", e);
             }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c20748b..e2112a59 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2382,17 +2382,16 @@
      * <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
      * not be used for calculating signal level. If multiple measures are set bit, the parameter
      * whose value is smallest is used to indicate the signal level.
+     * <UL>
+     *  <LI>RSRP = 1 << 0</LI>
+     *  <LI>RSRQ = 1 << 1</LI>
+     *  <LI>RSSNR = 1 << 2</LI>
+     * </UL>
+     * <p> The value of this key must be bitwise OR of {@link CellSignalStrengthLte#USE_RSRP},
+     * {@link CellSignalStrengthLte#USE_RSRQ}, {@link CellSignalStrengthLte#USE_RSSNR}.
      *
-     *  RSRP = 1 << 0,
-     *  RSRQ = 1 << 1,
-     *  RSSNR = 1 << 2,
-     *
-     *  The value of this key must be bitwise OR of {@link CellSignalStrengthLte#USE_RSRP},
-     *  {@link CellSignalStrengthLte#USE_RSRQ}, {@link CellSignalStrengthLte#USE_RSSNR}.
-     *
-     * For example, if both RSRP and RSRQ are used, the value of key is 3 (1 << 0 | 1 << 1).
-     * If the key is invalid or not configured, a default value (RSRP = 1 << 0)
-     * will apply.
+     * <p> For example, if both RSRP and RSRQ are used, the value of key is 3 (1 << 0 | 1 << 1).
+     * If the key is invalid or not configured, a default value (RSRP = 1 << 0) will apply.
      *
      * @hide
      */
@@ -2401,16 +2400,18 @@
 
     /**
      * List of 4 customized 5G SS reference signal received power (SSRSRP) thresholds.
-     *
+     * <p>
      * Reference: 3GPP TS 38.215
-     *
+     * <p>
      * 4 threshold integers must be within the boundaries [-140 dB, -44 dB], and the levels are:
-     *     "NONE: [-140, threshold1]"
-     *     "POOR: (threshold1, threshold2]"
-     *     "MODERATE: (threshold2, threshold3]"
-     *     "GOOD:  (threshold3, threshold4]"
-     *     "EXCELLENT:  (threshold4, -44]"
-     *
+     * <UL>
+     *     <LI>"NONE: [-140, threshold1]"</LI>
+     *     <LI>"POOR: (threshold1, threshold2]"</LI>
+     *     <LI>"MODERATE: (threshold2, threshold3]"</LI>
+     *     <LI>"GOOD:  (threshold3, threshold4]"</LI>
+     *     <LI>"EXCELLENT:  (threshold4, -44]"</LI>
+     * </UL>
+     * <p>
      * This key is considered invalid if the format is violated. If the key is invalid or
      * not configured, a default value set will apply.
      */
@@ -2419,16 +2420,18 @@
 
     /**
      * List of 4 customized 5G SS reference signal received quality (SSRSRQ) thresholds.
-     *
+     * <p>
      * Reference: 3GPP TS 38.215
-     *
+     * <p>
      * 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are:
-     *     "NONE: [-20, threshold1]"
-     *     "POOR: (threshold1, threshold2]"
-     *     "MODERATE: (threshold2, threshold3]"
-     *     "GOOD:  (threshold3, threshold4]"
-     *     "EXCELLENT:  (threshold4, -3]"
-     *
+     * <UL>
+     *     <LI>"NONE: [-20, threshold1]"</LI>
+     *     <LI>"POOR: (threshold1, threshold2]"</LI>
+     *     <LI>"MODERATE: (threshold2, threshold3]"</LI>
+     *     <LI>"GOOD:  (threshold3, threshold4]"</LI>
+     *     <LI>"EXCELLENT:  (threshold4, -3]"</LI>
+     * </UL>
+     * <p>
      * This key is considered invalid if the format is violated. If the key is invalid or
      * not configured, a default value set will apply.
      */
@@ -2437,17 +2440,19 @@
 
     /**
      * List of 4 customized 5G SS signal-to-noise and interference ratio (SSSINR) thresholds.
-     *
+     * <p>
      * Reference: 3GPP TS 38.215,
      *            3GPP TS 38.133 10.1.16.1
-     *
+     * <p>
      * 4 threshold integers must be within the boundaries [-23 dB, 40 dB], and the levels are:
-     *     "NONE: [-23, threshold1]"
-     *     "POOR: (threshold1, threshold2]"
-     *     "MODERATE: (threshold2, threshold3]"
-     *     "GOOD:  (threshold3, threshold4]"
-     *     "EXCELLENT:  (threshold4, 40]"
-     *
+     * <UL>
+     *     <LI>"NONE: [-23, threshold1]"</LI>
+     *     <LI>"POOR: (threshold1, threshold2]"</LI>
+     *     <LI>"MODERATE: (threshold2, threshold3]"</LI>
+     *     <LI>"GOOD:  (threshold3, threshold4]"</LI>
+     *     <LI>"EXCELLENT:  (threshold4, 40]"</LI>
+     * </UL>
+     * <p>
      * This key is considered invalid if the format is violated. If the key is invalid or
      * not configured, a default value set will apply.
      */
@@ -2462,19 +2467,19 @@
      * <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
      * not be used for calculating signal level. If multiple measures are set bit, the parameter
      * whose value is smallest is used to indicate the signal level.
-     *
-     *  SSRSRP = 1 << 0,
-     *  SSRSRQ = 1 << 1,
-     *  SSSINR = 1 << 2,
-     *
+     * <UL>
+     *  <LI>SSRSRP = 1 << 0</LI>
+     *  <LI>SSRSRQ = 1 << 1</LI>
+     *  <LI>SSSINR = 1 << 2</LI>
+     * </UL>
      *  The value of this key must be bitwise OR of {@link CellSignalStrengthNr#USE_SSRSRP},
      *  {@link CellSignalStrengthNr#USE_SSRSRQ}, {@link CellSignalStrengthNr#USE_SSSINR}.
      *
-     * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+     * <p> For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
      * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
      *
-     *  Reference: 3GPP TS 38.215,
-     *             3GPP TS 38.133 10.1.16.1
+     * <p> Reference: 3GPP TS 38.215,
+     *                3GPP TS 38.133 10.1.16.1
      *
      * @hide
      */
@@ -4157,7 +4162,7 @@
                 return null;
             }
             return loader.getConfigForSubIdWithFeature(subId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             Rlog.e(TAG, "Error getting config for subId " + subId + ": "
                     + ex.toString());
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 34bac5d..3984bd7 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -19,9 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.content.Context;
 import android.telephony.SubscriptionManager;
 
@@ -44,8 +42,6 @@
      * issues.
      * @hide
      */
-    @SystemApi
-    @TestApi
     // Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have
     // this value hard-coded in BroadcastReceiver.
     @SuppressLint("ActionValue")
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index 87d94bfd..c75de42 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -234,6 +234,9 @@
      * this method to facilitate the creation of {@link NetworkServiceProvider} instances. The system
      * will call this method after binding the network service for each active SIM slot id.
      *
+     * This methead is guaranteed to be invoked in {@link NetworkService}'s internal handler thread
+     * whose looper can be retrieved with {@link Looper.myLooper()} when override this method.
+     *
      * @param slotIndex SIM slot id the network service associated with.
      * @return Network service object. Null if failed to create the provider (e.g. invalid slot
      * index)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5a840de..01a40f5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1144,7 +1144,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1178,7 +1178,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1212,7 +1212,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1236,7 +1236,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 result = iSub.getAllSubInfoList(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1322,7 +1322,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1373,7 +1373,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1491,7 +1491,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 result = iSub.getAllSubInfoCount(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1520,7 +1520,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2275,7 +2275,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 resultValue = iSub.getSubscriptionProperty(subId, propKey,
-                        context.getOpPackageName(), context.getFeatureId());
+                        context.getOpPackageName(), context.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2439,7 +2439,7 @@
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
                 return iSub.isActiveSubId(subId, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
         }
@@ -2702,13 +2702,14 @@
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions() {
         String contextPkg = mContext != null ? mContext.getOpPackageName() : "<unknown>";
-        String contextFeature = mContext != null ? mContext.getFeatureId() : null;
+        String contextAttributionTag = mContext != null ? mContext.getAttributionTag() : null;
         List<SubscriptionInfo> subInfoList = null;
 
         try {
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
-                subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature);
+                subInfoList = iSub.getOpportunisticSubscriptions(contextPkg,
+                        contextAttributionTag);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2947,7 +2948,7 @@
     public @NonNull List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid) {
         Preconditions.checkNotNull(groupUuid, "groupUuid can't be null");
         String contextPkg = mContext != null ? mContext.getOpPackageName() : "<unknown>";
-        String contextFeature = mContext != null ? mContext.getFeatureId() : null;
+        String contextAttributionTag = mContext != null ? mContext.getAttributionTag() : null;
         if (VDBG) {
             logd("[getSubscriptionsInGroup]+ groupUuid:" + groupUuid);
         }
@@ -2956,7 +2957,8 @@
         try {
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
-                result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature);
+                result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg,
+                        contextAttributionTag);
             } else {
                 if (!isSystemProcess()) {
                     throw new IllegalStateException("telephony service is null.");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index db5a047..3f106f7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -345,10 +345,10 @@
         mSubId = subId;
         Context appContext = context.getApplicationContext();
         if (appContext != null) {
-            if (Objects.equals(context.getFeatureId(), appContext.getFeatureId())) {
+            if (Objects.equals(context.getAttributionTag(), appContext.getAttributionTag())) {
                 mContext = appContext;
             } else {
-                mContext = appContext.createFeatureContext(context.getFeatureId());
+                mContext = appContext.createAttributionContext(context.getAttributionTag());
             }
         } else {
             mContext = context;
@@ -393,12 +393,12 @@
         }
     }
 
-    private String getFeatureId() {
+    private String getAttributionTag() {
         // For legacy reasons the TelephonyManager has API for getting
         // a static instance with no context set preventing us from
-        // getting the feature Id.
+        // getting the attribution tag.
         if (mContext != null) {
-            return mContext.getFeatureId();
+            return mContext.getAttributionTag();
         }
         return null;
     }
@@ -1896,7 +1896,7 @@
 
         try {
             return telephony.getDeviceSoftwareVersionForSlot(slotIndex, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1938,7 +1938,7 @@
             if (telephony == null)
                 return null;
             return telephony.getDeviceIdWithFeature(mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1983,7 +1983,7 @@
             if (info == null)
                 return null;
             return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2041,7 +2041,7 @@
         if (telephony == null) return null;
 
         try {
-            return telephony.getImeiForSlot(slotIndex, getOpPackageName(), getFeatureId());
+            return telephony.getImeiForSlot(slotIndex, getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2135,7 +2135,8 @@
         if (telephony == null) return null;
 
         try {
-            String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName(), getFeatureId());
+            String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName(),
+                    getAttributionTag());
             if (TextUtils.isEmpty(meid)) {
                 Log.d(TAG, "getMeid: return null because MEID is not available");
                 return null;
@@ -2237,7 +2238,7 @@
             if (info == null)
                 return null;
             String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Rlog.v(TAG, "Nai = " + nai);
             }
@@ -2271,7 +2272,7 @@
             }
 
             CellIdentity cellIdentity = telephony.getCellLocation(mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
             CellLocation cl = cellIdentity.asCellLocation();
             if (cl == null || cl.isEmpty()) {
                 Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
@@ -2355,7 +2356,7 @@
             if (telephony == null)
                 return null;
             return telephony.getNeighboringCellInfo(mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2961,7 +2962,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -3026,7 +3027,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getDataNetworkTypeForSubscriber(subId, getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -3063,7 +3064,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getVoiceNetworkTypeForSubscriber(subId, getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -3849,7 +3850,7 @@
             if (info == null)
                 return null;
             return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -3893,7 +3894,7 @@
             if (telephony == null)
                 return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
             return telephony.getLteOnCdmaModeForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
@@ -4122,7 +4123,7 @@
             if (info == null)
                 return null;
             return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4290,7 +4291,7 @@
             if (info == null)
                 return null;
             return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4314,7 +4315,7 @@
             if (info == null)
                 return null;
             return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4365,7 +4366,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null)
                 number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName(),
-                         mContext.getFeatureId());
+                         mContext.getAttributionTag());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -4377,7 +4378,7 @@
             if (info == null)
                 return null;
             return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4456,7 +4457,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null)
                 alphaTag = telephony.getLine1AlphaTagForDisplay(subId,
-                        getOpPackageName(), getFeatureId());
+                        getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -4468,7 +4469,7 @@
             if (info == null)
                 return null;
             return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4498,7 +4499,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null)
                 return telephony.getMergedSubscriberIds(getSubId(), getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -4555,7 +4556,7 @@
             IPhoneSubInfo info = getSubscriberInfoService();
             if (info == null)
                 return null;
-            return info.getMsisdnForSubscriber(subId, getOpPackageName(), getFeatureId());
+            return info.getMsisdnForSubscriber(subId, getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4590,7 +4591,7 @@
             if (info == null)
                 return null;
             return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -4715,7 +4716,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getVisualVoicemailPackageName(mContext.getOpPackageName(),
-                        getFeatureId(), getSubId());
+                        getAttributionTag(), getSubId());
             }
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -5152,7 +5153,7 @@
             if (telephony == null)
                 return 0;
             return telephony.getVoiceMessageCountForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             return 0;
         } catch (NullPointerException ex) {
@@ -5189,7 +5190,7 @@
             if (info == null)
                 return null;
             return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -5279,8 +5280,8 @@
      *      not present or not loaded
      * @hide
      */
+    @UnsupportedAppUsage
     @Nullable
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String[] getIsimImpu() {
         try {
@@ -5572,7 +5573,7 @@
                 (TelephonyRegistryManager)
                         mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
         if (telephonyRegistry != null) {
-            telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getFeatureId(),
+            telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getAttributionTag(),
                     listener, events, notifyNow);
         } else {
             Rlog.w(TAG, "telephony registry not ready.");
@@ -5605,7 +5606,7 @@
             if (telephony == null)
                 return -1;
             return telephony.getCdmaEriIconIndexForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
@@ -5629,7 +5630,7 @@
             if (telephony == null)
                 return -1;
             return telephony.getCdmaEriIconModeForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
@@ -5661,7 +5662,7 @@
             if (telephony == null)
                 return null;
             return telephony.getCdmaEriTextForSubscriber(subId, getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return null;
@@ -5753,7 +5754,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getAllCellInfo(getOpPackageName(), getFeatureId());
+            return telephony.getAllCellInfo(getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -5853,7 +5854,7 @@
                                 Binder.restoreCallingIdentity(identity);
                             }
                         }
-                    }, getOpPackageName(), getFeatureId());
+                    }, getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
         }
     }
@@ -5904,7 +5905,7 @@
                                 Binder.restoreCallingIdentity(identity);
                             }
                         }
-                    }, getOpPackageName(), getFeatureId(), workSource);
+                    }, getOpPackageName(), getAttributionTag(), workSource);
         } catch (RemoteException ex) {
         }
     }
@@ -7190,7 +7191,7 @@
             if (telephony == null)
                 return null;
             return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName(),
-                    getFeatureId());
+                    getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -7224,7 +7225,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null) return -1;
             return telephony.setForbiddenPlmns(
-                    getSubId(), APPTYPE_USIM, fplmns, getOpPackageName(), getFeatureId());
+                    getSubId(), APPTYPE_USIM, fplmns, getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage());
         } catch (NullPointerException ex) {
@@ -7245,7 +7246,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return new String[0];
-            return telephony.getPcscfAddress(apnType, getOpPackageName(), getFeatureId());
+            return telephony.getPcscfAddress(apnType, getOpPackageName(), getAttributionTag());
         } catch (RemoteException e) {
             return new String[0];
         }
@@ -7818,7 +7819,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getAvailableNetworks RemoteException", ex);
@@ -7873,7 +7874,7 @@
             }
         }
         return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback,
-                getOpPackageName(), getFeatureId());
+                getOpPackageName(), getAttributionTag());
     }
 
     /**
@@ -8627,7 +8628,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.isRadioOnWithFeature(getOpPackageName(), getFeatureId());
+                return telephony.isRadioOnWithFeature(getOpPackageName(), getAttributionTag());
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isRadioOn", e);
         }
@@ -8921,7 +8922,10 @@
     }
 
     /**
-     * Shut down all the live radios over all the slot index.
+     * Shut down all the live radios over all the slot indexes.
+     *
+     * <p>To know when the radio has completed powering off, use
+     * {@link PhoneStateListener#LISTEN_SERVICE_STATE LISTEN_SERVICE_STATE}.
      *
      * @hide
      */
@@ -8934,7 +8938,8 @@
                 telephony.shutdownMobileRadios();
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#shutdownMobileRadios", e);
+            Log.e(TAG, "Error calling ITelephony#shutdownAllRadios", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -8953,7 +8958,8 @@
                 return telephony.needMobileRadioShutdown();
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#needMobileRadioShutdown", e);
+            Log.e(TAG, "Error calling ITelephony#isAnyRadioPoweredOn", e);
+            e.rethrowAsRuntimeException();
         }
         return false;
     }
@@ -8996,7 +9002,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
@@ -9183,7 +9189,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @CdmaRoamingMode int getCdmaRoamingMode() {
         int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT;
@@ -9212,7 +9217,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean setCdmaRoamingMode(@CdmaRoamingMode int mode) {
         try {
@@ -9238,19 +9242,16 @@
     /** Used for CDMA subscription mode, it'll be UNKNOWN if there is no Subscription source.
      * @hide
      */
-    @SystemApi
     public static final int CDMA_SUBSCRIPTION_UNKNOWN  = -1;
 
     /** Used for CDMA subscription mode: RUIM/SIM (default)
      * @hide
      */
-    @SystemApi
     public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0;
 
     /** Used for CDMA subscription mode: NV -> non-volatile memory
      * @hide
      */
-    @SystemApi
     public static final int CDMA_SUBSCRIPTION_NV       = 1;
 
     /** @hide */
@@ -9269,7 +9270,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean setCdmaSubscriptionMode(@CdmaSubscription int mode) {
         try {
@@ -9387,7 +9387,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.isVideoCallingEnabled(getOpPackageName(), getFeatureId());
+                return telephony.isVideoCallingEnabled(getOpPackageName(), getAttributionTag());
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e);
         }
@@ -9404,7 +9404,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.canChangeDtmfToneLength(mSubId, getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
@@ -9423,7 +9423,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.isWorldPhone(mSubId, getOpPackageName(), getFeatureId());
+                return telephony.isWorldPhone(mSubId, getOpPackageName(), getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
@@ -10151,7 +10151,8 @@
             ITelephony service = getITelephony();
             if (service != null) {
                 retval = service.getSubIdForPhoneAccountHandle(
-                        phoneAccountHandle, mContext.getOpPackageName(), mContext.getFeatureId());
+                        phoneAccountHandle, mContext.getOpPackageName(),
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "getSubscriptionId RemoteException", ex);
@@ -10292,7 +10293,7 @@
             ITelephony service = getITelephony();
             if (service != null) {
                 return service.getServiceStateForSubscriber(subId, getOpPackageName(),
-                        getFeatureId());
+                        getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getServiceStateForSubscriber", e);
@@ -11013,7 +11014,8 @@
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.getClientRequestStats(getOpPackageName(), getFeatureId(), subId);
+                return service.getClientRequestStats(getOpPackageName(), getAttributionTag(),
+                        subId);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getClientRequestStats", e);
@@ -11124,21 +11126,21 @@
     }
 
     /**
-     * Checks whether cellular data connection is enabled in the device.
+     * Checks whether cellular data connection is allowed in the device.
      *
-     * Whether cellular data connection is enabled, meaning upon request whether will try to setup
-     * metered data connection considering all factors below:
-     * 1) User turned on data setting {@link #isDataEnabled}.
-     * 2) Carrier allows data to be on.
-     * 3) Network policy.
-     * And possibly others.
-     *
-     * @return {@code true} if the overall data connection is capable; {@code false} if not.
+     * <p>Whether cellular data connection is allowed considers all factors below:
+     * <UL>
+     *   <LI>User turned on data setting {@link #isDataEnabled}.</LI>
+     *   <LI>Carrier allows data to be on.</LI>
+     *   <LI>Network policy.</LI>
+     *   <LI>And possibly others.</LI>
+     * </UL>
+     * @return {@code true} if the overall data connection is allowed; {@code false} if not.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isDataConnectionEnabled() {
+    public boolean isDataConnectionAllowed() {
         boolean retVal = false;
         try {
             int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
@@ -11146,8 +11148,9 @@
             if (telephony != null)
                 retVal = telephony.isDataEnabled(subId);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error isDataConnectionEnabled", e);
+            Log.e(TAG, "Error isDataConnectionAllowed", e);
         } catch (NullPointerException e) {
+            return false;
         }
         return retVal;
     }
@@ -11298,7 +11301,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getNumberOfModemsWithSimultaneousDataConnections(
-                        getSubId(), getOpPackageName(), getFeatureId());
+                        getSubId(), getOpPackageName(), getAttributionTag());
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
@@ -11728,7 +11731,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getEmergencyNumberList(mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
@@ -11783,7 +11786,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 emergencyNumberList = telephony.getEmergencyNumberList(
-                        mContext.getOpPackageName(), mContext.getFeatureId());
+                        mContext.getOpPackageName(), mContext.getAttributionTag());
                 if (emergencyNumberList != null) {
                     for (Integer subscriptionId : emergencyNumberList.keySet()) {
                         List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId);
@@ -11876,7 +11879,7 @@
     }
 
     /**
-     * A test API to return the emergency number db version.
+     * Returns the emergency number database version.
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
@@ -11885,6 +11888,7 @@
      */
     @TestApi
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public int getEmergencyNumberDbVersion() {
         try {
             ITelephony telephony = getITelephony();
@@ -12091,13 +12095,13 @@
     })
     public int getPreferredOpportunisticDataSubscription() {
         String packageName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
-        String featureId = mContext != null ? mContext.getFeatureId() : null;
+        String attributionTag = mContext != null ? mContext.getAttributionTag() : null;
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
             IOns iOpportunisticNetworkService = getIOns();
             if (iOpportunisticNetworkService != null) {
                 subId = iOpportunisticNetworkService.getPreferredDataSubscriptionId(
-                        packageName, featureId);
+                        packageName, attributionTag);
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getPreferredDataSubscriptionId RemoteException", ex);
@@ -12227,7 +12231,7 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                        mContext.getAttributionTag());
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "enableModem RemoteException", ex);
@@ -12332,7 +12336,7 @@
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.isMultiSimSupported(getOpPackageName(), getFeatureId());
+                return service.isMultiSimSupported(getOpPackageName(), getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "isMultiSimSupported RemoteException", e);
@@ -12384,7 +12388,7 @@
             ITelephony service = getITelephony();
             if (service != null) {
                 return service.doesSwitchMultiSimConfigTriggerReboot(getSubId(),
-                        getOpPackageName(), getFeatureId());
+                        getOpPackageName(), getAttributionTag());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "doesSwitchMultiSimConfigTriggerReboot RemoteException", e);
@@ -12453,7 +12457,6 @@
      * @throws {@link SecurityException} if the caller is not the system or phone process.
      * @hide
      */
-    @SystemApi
     @TestApi
     // TODO: add new permission tag indicating that this is system-only.
     public @NonNull List<ApnSetting> getDevicePolicyOverrideApns(@NonNull Context context) {
@@ -12484,7 +12487,6 @@
      * @throws {@link SecurityException} if the caller is not the system or phone process.
      * @hide
      */
-    @SystemApi
     @TestApi
     // TODO: add new permission tag indicating that this is system-only.
     public int addDevicePolicyOverrideApn(@NonNull Context context,
@@ -12515,7 +12517,6 @@
      * @throws {@link SecurityException} if the caller is not the system or phone process.
      * @hide
      */
-    @SystemApi
     @TestApi
     // TODO: add new permission tag indicating that this is system-only.
     public boolean modifyDevicePolicyOverrideApn(@NonNull Context context, int apnId,
@@ -12879,7 +12880,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean setDataAllowedDuringVoiceCall(boolean allow) {
         try {
@@ -12908,7 +12908,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isDataAllowedInVoiceCall() {
         try {
@@ -12955,7 +12954,6 @@
      * The IccLock state or password was changed successfully.
      * @hide
      */
-    @SystemApi
     public static final int CHANGE_ICC_LOCK_SUCCESS = Integer.MAX_VALUE;
 
     /**
@@ -12968,7 +12966,6 @@
      *
      * @hide
      */
-    @SystemApi
     @WorkerThread
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isIccLockEnabled() {
@@ -13005,7 +13002,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public int setIccLockEnabled(boolean enabled, @NonNull String password) {
         checkNotNull(password, "setIccLockEnabled password can't be null.");
@@ -13039,7 +13035,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public int changeIccLockPassword(@NonNull String oldPassword, @NonNull String newPassword) {
         checkNotNull(oldPassword, "changeIccLockPassword oldPassword can't be null.");
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 6c4e7ce..f56bbe1 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -458,6 +458,9 @@
      * this method to facilitate the creation of {@link DataServiceProvider} instances. The system
      * will call this method after binding the data service for each active SIM slot id.
      *
+     * This methead is guaranteed to be invoked in {@link DataService}'s internal handler thread
+     * whose looper can be retrieved with {@link Looper.myLooper()} when override this method.
+     *
      * @param slotIndex SIM slot id the data service associated with.
      * @return Data service object. Null if failed to create the provider (e.g. invalid slot index)
      */
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 4b5303f..bd531da 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -21,7 +21,6 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SuppressLint;
@@ -124,7 +123,7 @@
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
          */
         @Override
-        public void onUnregistered(@Nullable ImsReasonInfo info) {
+        public void onUnregistered(@NonNull ImsReasonInfo info) {
         }
 
         /**
@@ -136,7 +135,7 @@
         @Override
         public void onTechnologyChangeFailed(
                 @AccessNetworkConstants.TransportType int imsTransportType,
-                @Nullable ImsReasonInfo info) {
+                @NonNull ImsReasonInfo info) {
         }
     }
 
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 00fa942..1a606b7 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -85,6 +85,7 @@
 
     /**
      * There is no existing configuration for the queried provisioning key.
+     * @hide
      */
     public static final int PROVISIONING_RESULT_UNKNOWN = -1;
 
@@ -120,6 +121,7 @@
      * Value is in String format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0;
 
@@ -143,6 +145,7 @@
      * Value is in String format.
      * @see #setProvisioningStringValue(int, String)
      * @see #getProvisioningStringValue(int)
+     * @hide
      */
     public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1;
 
@@ -154,6 +157,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_SESSION_TIMER_SEC = 2;
 
@@ -165,6 +169,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3;
 
@@ -176,6 +181,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4;
 
@@ -184,6 +190,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5;
 
@@ -192,6 +199,7 @@
      * Value is in boolean format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_ENABLE_SILENT_REDIAL = 6;
 
@@ -207,6 +215,7 @@
      * The value is an integer.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_T1_TIMER_VALUE_MS = 7;
 
@@ -218,6 +227,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_T2_TIMER_VALUE_MS = 8;
 
@@ -229,6 +239,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_TF_TIMER_VALUE_MS = 9;
 
@@ -241,6 +252,7 @@
      * {@link #PROVISIONING_VALUE_DISABLED} to disable VoLTE provisioning.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_VOLTE_PROVISIONING_STATUS = 10;
 
@@ -253,6 +265,7 @@
      * {@link #PROVISIONING_VALUE_DISABLED} to disable VT provisioning.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_VT_PROVISIONING_STATUS = 11;
 
@@ -261,6 +274,7 @@
      * Value is in String format.
      * @see #setProvisioningStringValue(int, String)
      * @see #getProvisioningStringValue(int)
+     * @hide
      */
     public static final int KEY_REGISTRATION_DOMAIN_NAME = 12;
 
@@ -270,18 +284,21 @@
      * Valid values are {@link #SMS_FORMAT_3GPP} and {@link #SMS_FORMAT_3GPP2}.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SMS_FORMAT = 13;
 
     /**
      * Value used with {@link #KEY_SMS_FORMAT} to indicate 3GPP2 SMS format is used.
      * See {@link android.telephony.SmsMessage#FORMAT_3GPP2} for more information.
+     * @hide
      */
     public static final int SMS_FORMAT_3GPP2 = 0;
 
     /**
      * Value used with {@link #KEY_SMS_FORMAT} to indicate 3GPP SMS format is used.
      * See {@link android.telephony.SmsMessage#FORMAT_3GPP} for more information.
+     * @hide
      */
     public static final int SMS_FORMAT_3GPP = 1;
 
@@ -290,6 +307,7 @@
      * Value is in Integer format. ON (1), OFF(0).
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SMS_OVER_IP_ENABLED = 14;
 
@@ -300,6 +318,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15;
 
@@ -310,6 +329,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16;
 
@@ -322,6 +342,7 @@
      * enabled.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17;
 
@@ -334,6 +355,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18;
 
@@ -345,6 +367,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19;
 
@@ -356,6 +379,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20;
 
@@ -366,6 +390,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21;
 
@@ -376,6 +401,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22;
 
@@ -387,6 +413,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23;
 
@@ -395,6 +422,7 @@
      * Value is in Integer format. Enable (1), Disable(0).
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24;
 
@@ -407,6 +435,7 @@
      * {@link #PROVISIONING_VALUE_DISABLED} to disable EAB provisioning.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_EAB_PROVISIONING_STATUS = 25;
 
@@ -440,6 +469,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28;
 
@@ -448,6 +478,7 @@
      * Value is in Integer format. On (1), OFF(0).
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_MOBILE_DATA_ENABLED = 29;
 
@@ -456,12 +487,14 @@
      * Value is in Integer format. Opted-in (1) Opted-out (0).
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30;
 
     /**
      * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
      * Value is in String format.
+     * @hide
      */
     public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31;
 
@@ -470,6 +503,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32;
 
@@ -479,6 +513,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33;
 
@@ -488,6 +523,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34;
 
@@ -496,6 +532,7 @@
      * Value is in integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
 
     public static final int KEY_RTP_SPEECH_START_PORT = 35;
@@ -505,6 +542,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RTP_SPEECH_END_PORT = 36;
 
@@ -514,6 +552,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37;
 
@@ -523,6 +562,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38;
 
@@ -532,6 +572,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39;
 
@@ -541,6 +582,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40;
 
@@ -550,6 +592,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41;
 
@@ -559,6 +602,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42;
 
@@ -568,6 +612,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43;
 
@@ -577,6 +622,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44;
 
@@ -586,6 +632,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45;
 
@@ -595,6 +642,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46;
 
@@ -603,6 +651,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47;
 
@@ -611,6 +660,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48;
 
@@ -619,6 +669,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49;
 
@@ -627,6 +678,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50;
 
@@ -635,6 +687,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51;
 
@@ -643,6 +696,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52;
 
@@ -651,12 +705,14 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53;
 
     /**
      * SMS Public Service Identity.
      * Value is in String format.
+     * @hide
      */
     public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54;
 
@@ -666,16 +722,19 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_VIDEO_QUALITY = 55;
 
     /**
      * Used with {@link #KEY_VIDEO_QUALITY} to indicate low video quality.
+     * @hide
      */
     public static final int VIDEO_QUALITY_LOW = 0;
 
     /**
      * Used with {@link #KEY_VIDEO_QUALITY} to indicate high video quality.
+     * @hide
      */
     public static final int VIDEO_QUALITY_HIGH = 1;
 
@@ -685,6 +744,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_LTE_THRESHOLD_1 = 56;
 
@@ -696,6 +756,7 @@
      *
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_LTE_THRESHOLD_2 = 57;
 
@@ -707,6 +768,7 @@
      *
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_LTE_THRESHOLD_3 = 58;
 
@@ -716,6 +778,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_1X_THRESHOLD = 59;
 
@@ -727,6 +790,7 @@
      *
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_WIFI_THRESHOLD_A = 60;
 
@@ -737,6 +801,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_WIFI_THRESHOLD_B = 61;
 
@@ -746,6 +811,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_LTE_EPDG_TIMER_SEC = 62;
 
@@ -755,12 +821,14 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_WIFI_EPDG_TIMER_SEC = 63;
 
     /**
      * 1x ePDG timer (in seconds).
      * Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+     * @hide
      */
     public static final int KEY_1X_EPDG_TIMER_SEC = 64;
 
@@ -769,6 +837,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_MULTIENDPOINT_ENABLED = 65;
 
@@ -777,6 +846,7 @@
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
+     * @hide
      */
     public static final int KEY_RTT_ENABLED = 66;
 
@@ -928,7 +998,7 @@
      *
      * @param key An integer that represents the provisioning key, which is defined by the OEM.
      * @return an integer value for the provided key, or
-     * {@link #PROVISIONING_RESULT_UNKNOWN} if the key doesn't exist.
+     * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} if the key doesn't exist.
      * @throws IllegalArgumentException if the key provided was invalid.
      */
     @WorkerThread
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 57b9b7a..dc36edf 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -19,8 +19,6 @@
 import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -37,8 +35,6 @@
  * Contains the User Capability Exchange capabilities corresponding to a contact's URI.
  * @hide
  */
-@SystemApi
-@TestApi
 public final class RcsContactUceCapability implements Parcelable {
 
     /** Supports 1-to-1 chat */
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 30306c7..05ab6bd 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -291,7 +291,7 @@
 
         try {
             imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
-                    mContext.getFeatureId(), contactNumbers, internalCallback);
+                    mContext.getAttributionTag(), contactNumbers, internalCallback);
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
             throw new ImsException("Remote IMS Service is not available",
@@ -352,7 +352,7 @@
         try {
             // Telephony.SimInfo#IMS_RCS_UCE_ENABLED can also be used to listen to changes to this.
             return imsRcsController.isUceSettingEnabled(mSubId, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling IImsRcsController#isUceSettingEnabled", e);
             throw new ImsException("Remote IMS Service is not available",
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 5c86ba7..1dbaff5 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -196,11 +196,11 @@
         }
 
         /**
-         * Notifies the framework when the IMS Provider is deregistered from the IMS network.
+         * Notifies the framework when the IMS Provider is unregistered from the IMS network.
          *
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
          */
-        public void onUnregistered(@Nullable ImsReasonInfo info) {
+        public void onUnregistered(@NonNull ImsReasonInfo info) {
         }
 
         /**
@@ -211,7 +211,7 @@
          */
         public void onTechnologyChangeFailed(
                 @AccessNetworkConstants.TransportType int imsTransportType,
-                @Nullable ImsReasonInfo info) {
+                @NonNull ImsReasonInfo info) {
         }
 
         /**
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 14a64d2..7069e0a 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -175,9 +175,11 @@
      */
     public final void onDeregistered(ImsReasonInfo info) {
         updateToDisconnectedState(info);
+        // ImsReasonInfo should never be null.
+        final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo();
         mCallbacks.broadcastAction((c) -> {
             try {
-                c.onDeregistered(info);
+                c.onDeregistered(reasonInfo);
             } catch (RemoteException e) {
                 Log.w(LOG_TAG, e + " " + "onRegistrationDisconnected() - Skipping " +
                         "callback.");
@@ -194,9 +196,10 @@
      */
     public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
             ImsReasonInfo info) {
+        final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo();
         mCallbacks.broadcastAction((c) -> {
             try {
-                c.onTechnologyChangeFailed(imsRadioTech, info);
+                c.onTechnologyChangeFailed(imsRadioTech, reasonInfo);
             } catch (RemoteException e) {
                 Log.w(LOG_TAG, e + " " + "onRegistrationChangeFailed() - Skipping " +
                         "callback.");
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index f13371c..8564f7a 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -44,52 +44,62 @@
 public class ImsUtImplBase {
     /**
      * Bar all incoming calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_ALL_INCOMING = 1;
 
     /**
      * Bar all outgoing calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_ALL_OUTGOING = 2;
 
     /**
      * Bar all outgoing international calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_OUTGOING_INTL = 3;
 
     /**
      * Bar all outgoing international calls, excluding those to the home PLMN country
      * (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4;
 
     /**
      * Bar all incoming calls when roaming (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5;
 
     /**
      * Enable Anonymous Communication Rejection (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6;
 
     /**
      * Bar all incoming and outgoing calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_ALL = 7;
 
     /**
      * Bar all outgoing service requests, including calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8;
 
     /**
      * Bar all incoming service requests, including calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9;
 
     /**
      * Bar specific incoming calls. (See 3GPP TS 24.611)
+     * @hide
      */
     public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10;
 
@@ -104,6 +114,7 @@
 
     /**
      * Constant used to denote an invalid return value.
+     * @hide
      */
     public static final int INVALID_RESULT = -1;
 
@@ -338,6 +349,7 @@
 
     /**
      * Updates the configuration of the call barring for specified service class with password.
+     * @hide
      */
     public int updateCallBarringWithPassword(int cbType, int action, @Nullable String[] barrList,
             int serviceClass, @NonNull String password) {
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
index 504bd17..b805744 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
@@ -38,38 +38,75 @@
 public class DummyBlobData {
     private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
 
-    private final Context mContext;
     private final Random mRandom;
     private final File mFile;
     private final long mFileSize;
-    private final String mLabel;
+    private final CharSequence mLabel;
 
     byte[] mFileDigest;
     long mExpiryTimeMs;
 
-    public DummyBlobData(Context context) {
-        this(context, new Random(0), "blob_" + System.nanoTime());
+    public DummyBlobData(Builder builder) {
+        mRandom = new Random(builder.getRandomSeed());
+        mFile = new File(builder.getContext().getFilesDir(), builder.getFileName());
+        mFileSize = builder.getFileSize();
+        mLabel = builder.getLabel();
     }
 
-    public DummyBlobData(Context context, long fileSize) {
-        this(context, fileSize, new Random(0), "blob_" + System.nanoTime(), "Test label");
-    }
+    public static class Builder {
+        private final Context mContext;
+        private int mRandomSeed = 0;
+        private long mFileSize = DEFAULT_SIZE_BYTES;
+        private CharSequence mLabel = "Test label";
+        private String mFileName = "blob_" + System.nanoTime();
 
-    public DummyBlobData(Context context, Random random, String fileName) {
-        this(context, DEFAULT_SIZE_BYTES, random, fileName, "Test label");
-    }
+        public Builder(Context context) {
+            mContext = context;
+        }
 
-    public DummyBlobData(Context context, Random random, String fileName, String label) {
-        this(context, DEFAULT_SIZE_BYTES, random, fileName, label);
-    }
+        public Context getContext() {
+            return mContext;
+        }
 
-    public DummyBlobData(Context context, long fileSize, Random random, String fileName,
-            String label) {
-        mContext = context;
-        mRandom = random;
-        mFile = new File(mContext.getFilesDir(), fileName);
-        mFileSize = fileSize;
-        mLabel = label;
+        public Builder setRandomSeed(int randomSeed) {
+            mRandomSeed = randomSeed;
+            return this;
+        }
+
+        public int getRandomSeed() {
+            return mRandomSeed;
+        }
+
+        public Builder setFileSize(int fileSize) {
+            mFileSize = fileSize;
+            return this;
+        }
+
+        public long getFileSize() {
+            return mFileSize;
+        }
+
+        public Builder setLabel(CharSequence label) {
+            mLabel = label;
+            return this;
+        }
+
+        public CharSequence getLabel() {
+            return mLabel;
+        }
+
+        public Builder setFileName(String fileName) {
+            mFileName = fileName;
+            return this;
+        }
+
+        public String getFileName() {
+            return mFileName;
+        }
+
+        public DummyBlobData build() {
+            return new DummyBlobData(this);
+        }
     }
 
     public void prepare() throws Exception {
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
index c35385c..654c1e2 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
@@ -16,7 +16,13 @@
 
 package com.android.utils.blob;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.blob.BlobHandle;
 import android.app.blob.BlobStoreManager;
+import android.app.blob.LeaseInfo;
+import android.content.Context;
+import android.content.res.Resources;
 import android.os.ParcelFileDescriptor;
 
 import java.io.FileInputStream;
@@ -56,4 +62,76 @@
             copy(in, out, lengthBytes);
         }
     }
+
+    public static void assertLeasedBlobs(BlobStoreManager blobStoreManager,
+            BlobHandle... expectedBlobHandles) throws IOException {
+        assertThat(blobStoreManager.getLeasedBlobs()).containsExactly(expectedBlobHandles);
+    }
+
+    public static void assertNoLeasedBlobs(BlobStoreManager blobStoreManager)
+            throws IOException {
+        assertThat(blobStoreManager.getLeasedBlobs()).isEmpty();
+    }
+
+    public static void acquireLease(Context context,
+            BlobHandle blobHandle, CharSequence description) throws IOException {
+        final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        blobStoreManager.acquireLease(blobHandle, description);
+
+        final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
+        assertLeaseInfo(leaseInfo, context.getPackageName(), 0,
+                Resources.ID_NULL, description);
+    }
+
+    public static void acquireLease(Context context,
+            BlobHandle blobHandle, int descriptionResId) throws IOException {
+        final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        blobStoreManager.acquireLease(blobHandle, descriptionResId);
+
+        final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
+        assertLeaseInfo(leaseInfo, context.getPackageName(), 0,
+                descriptionResId, context.getString(descriptionResId));
+    }
+
+    public static void acquireLease(Context context,
+            BlobHandle blobHandle, CharSequence description,
+            long expiryTimeMs) throws IOException {
+        final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        blobStoreManager.acquireLease(blobHandle, description, expiryTimeMs);
+
+        final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
+        assertLeaseInfo(leaseInfo, context.getPackageName(), expiryTimeMs,
+                Resources.ID_NULL, description);
+    }
+
+    public static void acquireLease(Context context,
+            BlobHandle blobHandle, int descriptionResId,
+            long expiryTimeMs) throws IOException {
+        final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        blobStoreManager.acquireLease(blobHandle, descriptionResId, expiryTimeMs);
+
+        final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
+        assertLeaseInfo(leaseInfo, context.getPackageName(), expiryTimeMs,
+                descriptionResId, context.getString(descriptionResId));
+    }
+
+    public static void releaseLease(Context context,
+            BlobHandle blobHandle) throws IOException {
+        final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
+                Context.BLOB_STORE_SERVICE);
+        blobStoreManager.releaseLease(blobHandle);
+        assertThat(blobStoreManager.getLeaseInfo(blobHandle)).isNull();
+    }
+
+    private static void assertLeaseInfo(LeaseInfo leaseInfo, String packageName,
+            long expiryTimeMs, int descriptionResId, CharSequence description) {
+        assertThat(leaseInfo.getPackageName()).isEqualTo(packageName);
+        assertThat(leaseInfo.getExpiryTimeMillis()).isEqualTo(expiryTimeMs);
+        assertThat(leaseInfo.getDescriptionResId()).isEqualTo(descriptionResId);
+        assertThat(leaseInfo.getDescription()).isEqualTo(description);
+    }
 }
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 5904916..c7e5a5e 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -322,7 +322,7 @@
 
                 mAtm.startActivityAndWait(null,
                         getInstrumentation().getContext().getBasePackageName(),
-                        getInstrumentation().getContext().getFeatureId(), mLaunchIntent,
+                        getInstrumentation().getContext().getAttributionTag(), mLaunchIntent,
                         mimeType, null, null, 0, mLaunchIntent.getFlags(), null, null,
                         UserHandle.USER_CURRENT_OR_SELF);
             } catch (RemoteException e) {
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 8cc8cf4..dfaac2c 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1063,6 +1063,20 @@
         assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
     }
 
+    /**
+     * Ensure that passing a null list of failed packages does not cause any mitigation logic to
+     * execute.
+     */
+    @Test
+    public void testNullFailedPackagesList() {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        watchdog.startObservingHealth(observer1, List.of(APP_A), LONG_DURATION);
+
+        raiseFatalFailureAndDispatch(watchdog, null, PackageWatchdog.FAILURE_REASON_APP_CRASH);
+        assertThat(observer1.mMitigatedPackages).isEmpty();
+    }
+
     private void adoptShellPermissions(String... permissions) {
         InstrumentationRegistry
                 .getInstrumentation()
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
index 6169671..3bc5309 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
@@ -66,7 +66,7 @@
         WindowManager.LayoutParams lp =
             new WindowManager.LayoutParams(500, 500, WindowManager.LayoutParams.TYPE_APPLICATION,
                     0, PixelFormat.OPAQUE);
-        mVr.addView(v, lp);
+        mVr.setView(v, lp);
     }
 
     @Override
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
index e415170..f254e4d 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
@@ -34,9 +34,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.Window;
 import android.view.WindowInsets;
-import android.view.WindowInsets.Type;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimation.Callback;
 import android.view.WindowInsetsAnimationControlListener;
@@ -101,7 +99,7 @@
                                 && !mRequestedController) {
                             mRequestedController = true;
                             v.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
-                                    1000, new LinearInterpolator(),
+                                    1000, new LinearInterpolator(), null /* cancellationSignal */,
                                     mCurrentRequest = new WindowInsetsAnimationControlListener() {
                                         @Override
                                         public void onReady(
@@ -208,7 +206,7 @@
                         if ((types & ime()) != 0 && !hasControl) {
                             hasControl = true;
                             controller.controlWindowInsetsAnimation(ime(), -1,
-                                    new LinearInterpolator(),
+                                    new LinearInterpolator(), null /* cancellationSignal */,
                                     new WindowInsetsAnimationControlListener() {
                                         @Override
                                         public void onReady(
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 99dac14..c74c112 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -367,6 +367,9 @@
                     -2, 100000L);
             fail("negative deprecation time should cause exception");
         } catch (IllegalArgumentException expected) { }
+
+        LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
+        assertEquals(100000L, addr.getDeprecationTime());
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
@@ -382,6 +385,9 @@
                     100000L, -2);
             fail("negative expiration time should cause exception");
         } catch (IllegalArgumentException expected) { }
+
+        LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
+        assertEquals(200000L, addr.getExpirationTime());
     }
 
     @Test
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index b81ca36..442ac56 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -35,6 +35,7 @@
 import android.net.ipmemorystore.NetworkAttributes;
 import android.net.ipmemorystore.NetworkAttributesParcelable;
 import android.net.ipmemorystore.Status;
+import android.net.networkstack.ModuleNetworkStackClient;
 import android.os.RemoteException;
 
 import androidx.test.filters.SmallTest;
@@ -67,7 +68,7 @@
     @Mock
     Context mMockContext;
     @Mock
-    NetworkStackClient mNetworkStackClient;
+    ModuleNetworkStackClient mModuleNetworkStackClient;
     @Mock
     IIpMemoryStore mMockService;
     @Mock
@@ -90,14 +91,14 @@
                 ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
                         .onIpMemoryStoreFetched(mMockService);
                 return null;
-            }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+            }).when(mModuleNetworkStackClient).fetchIpMemoryStore(any());
         } else {
-            doNothing().when(mNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
+            doNothing().when(mModuleNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
         }
         mStore = new IpMemoryStore(mMockContext) {
             @Override
-            protected NetworkStackClient getNetworkStackClient() {
-                return mNetworkStackClient;
+            protected ModuleNetworkStackClient getModuleNetworkStackClient(Context ctx) {
+                return mModuleNetworkStackClient;
             }
         };
     }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8c0c36b..671c564 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,8 +23,6 @@
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
 import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
@@ -100,6 +98,7 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.startsWith;
 import static org.mockito.Matchers.anyInt;
@@ -2426,7 +2425,7 @@
         assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
         assertTrue(testFactory.getMyStartRequested());
 
-        testFactory.unregister();
+        testFactory.terminate();
         if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
         handlerThread.quit();
     }
@@ -2452,6 +2451,38 @@
     }
 
     @Test
+    public void testNetworkFactoryUnregister() throws Exception {
+        final NetworkCapabilities filter = new NetworkCapabilities();
+        filter.clearAll();
+
+        final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
+        handlerThread.start();
+
+        // Checks that calling setScoreFilter on a NetworkFactory immediately before closing it
+        // does not crash.
+        for (int i = 0; i < 100; i++) {
+            final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+                    mServiceContext, "testFactory", filter);
+            // Register the factory and don't be surprised when the default request arrives.
+            testFactory.register();
+            testFactory.expectAddRequestsWithScores(0);
+            testFactory.waitForNetworkRequests(1);
+
+            testFactory.setScoreFilter(42);
+            testFactory.terminate();
+
+            if (i % 2 == 0) {
+                try {
+                    testFactory.register();
+                    fail("Re-registering terminated NetworkFactory should throw");
+                } catch (IllegalStateException expected) {
+                }
+            }
+        }
+        handlerThread.quit();
+    }
+
+    @Test
     public void testNoMutableNetworkRequests() throws Exception {
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
         NetworkRequest request1 = new NetworkRequest.Builder()
@@ -3483,7 +3514,7 @@
         cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         assertLength(1, mCm.getAllNetworks());
 
-        testFactory.unregister();
+        testFactory.terminate();
         mCm.unregisterNetworkCallback(cellNetworkCallback);
         handlerThread.quit();
     }
@@ -3724,7 +3755,7 @@
         mCm.requestNetwork(nr, networkCallback, timeoutMs);
 
         // pass timeout and validate that UNAVAILABLE is called
-        networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, null);
+        networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
 
         // create a network satisfying request - validate that request not triggered
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -3815,7 +3846,7 @@
             // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
             testFactory.triggerUnfulfillable(requests.get(newRequestId));
 
-            networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, null);
+            networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
             testFactory.waitForRequests();
 
             // unregister network callback - a no-op (since already freed by the
@@ -3823,7 +3854,7 @@
             mCm.unregisterNetworkCallback(networkCallback);
         }
 
-        testFactory.unregister();
+        testFactory.terminate();
         handlerThread.quit();
     }
 
@@ -6870,8 +6901,13 @@
         HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
 
         // Verify onConnectivityReport fired
-        verify(mConnectivityDiagnosticsCallback)
-                .onConnectivityReport(any(ConnectivityReport.class));
+        verify(mConnectivityDiagnosticsCallback).onConnectivityReport(
+                argThat(report -> {
+                    final NetworkCapabilities nc = report.getNetworkCapabilities();
+                    return nc.getUids() == null
+                            && nc.getAdministratorUids().isEmpty()
+                            && nc.getOwnerUid() == Process.INVALID_UID;
+                }));
     }
 
     @Test
@@ -6886,7 +6922,13 @@
         HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
 
         // Verify onDataStallSuspected fired
-        verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(any(DataStallReport.class));
+        verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
+                argThat(report -> {
+                    final NetworkCapabilities nc = report.getNetworkCapabilities();
+                    return nc.getUids() == null
+                            && nc.getAdministratorUids().isEmpty()
+                            && nc.getOwnerUid() == Process.INVALID_UID;
+                }));
     }
 
     @Test
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 5aa32f8..bcfce66 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -366,8 +366,12 @@
   });
   manifest_action["instrumentation"]["meta-data"] = meta_data_action;
 
+  // TODO moltmann: Remove
   manifest_action["feature"];
   manifest_action["feature"]["inherit-from"];
+
+  manifest_action["attribution"];
+  manifest_action["attribution"]["inherit-from"];
   manifest_action["original-package"];
   manifest_action["overlay"];
   manifest_action["protected-broadcast"];
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
index 950361c..eeb006e 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -1,7 +1,32 @@
+# used by wifi-service
+rule android.net.DhcpResultsParcelable* @0
+rule android.net.DhcpResults* com.android.server.x.wifi.net.DhcpResults@1
 rule android.net.InterfaceConfigurationParcel* @0
 rule android.net.InterfaceConfiguration* com.android.server.x.wifi.net.InterfaceConfiguration@1
+rule android.net.IpMemoryStore* com.android.server.x.wifi.net.IpMemoryStore@1
+rule android.net.NetworkMonitorManager* com.android.server.x.wifi.net.NetworkMonitorManager@1
+rule android.net.TcpKeepalivePacketData* com.android.server.x.wifi.net.TcpKeepalivePacketData@1
 rule android.net.NetworkFactory* com.android.server.x.wifi.net.NetworkFactory@1
+rule android.net.ip.IpClientCallbacks* com.android.server.x.wifi.net.ip.IpClientCallbacks@1
+rule android.net.ip.IpClientManager* com.android.server.x.wifi.net.ip.IpClientManager@1
+rule android.net.ip.IpClientUtil* com.android.server.x.wifi.net.ip.IpClientUtil@1
+rule android.net.shared.InetAddressUtils* com.android.server.x.wifi.net.shared.InetAddressUtils@1
+rule android.net.shared.InitialConfiguration* com.android.server.x.wifi.net.shared.InitialConfiguration@1
+rule android.net.shared.IpConfigurationParcelableUtil* com.android.server.x.wifi.net.shared.IpConfigurationParcelableUtil@1
+rule android.net.shared.LinkPropertiesParcelableUtil* com.android.server.x.wifi.net.shared.LinkPropertiesParcelableUtil@1
+rule android.net.shared.ParcelableUtil* com.android.server.x.wifi.net.shared.ParcelableUtil@1
+rule android.net.shared.NetdUtils* com.android.server.x.wifi.net.shared.NetdUtils@1
+rule android.net.shared.NetworkMonitorUtils* com.android.server.x.wifi.net.shared.NetworkMonitorUtils@1
+rule android.net.shared.ParcelableUtil* com.android.server.x.wifi.net.shared.ParcelableUtil@1
+rule android.net.shared.PrivateDnsConfig* com.android.server.x.wifi.net.shared.PrivateDnsConfig@1
+rule android.net.shared.ProvisioningConfiguration* com.android.server.x.wifi.net.shared.ProvisioningConfiguration@1
+rule android.net.shared.RouteUtils* com.android.server.x.wifi.net.shared.RouteUtils@1
+rule android.net.util.KeepalivePacketDataUtil* com.android.server.x.wifi.net.util.KeepalivePacketDataUtil@1
+rule android.net.util.NetworkConstants* com.android.server.x.wifi.net.util.NetworkConstants@1
+rule android.net.util.InterfaceParams* com.android.server.x.wifi.net.util.InterfaceParams@1
+rule android.net.util.SharedLog* com.android.server.x.wifi.net.util.SharedLog@1
 rule android.net.util.NetUtils* com.android.server.x.wifi.net.util.NetUtils@1
+rule android.net.util.IpUtils* com.android.server.x.wifi.net.util.IpUtils@1
 
 # We don't jar-jar the entire package because, we still use some classes (like
 # AsyncChannel in com.android.internal.util) from these packages which are not
@@ -29,7 +54,6 @@
 # Use our statically linked PlatformProperties library
 rule android.sysprop.** com.android.server.x.wifi.sysprop.@1
 
-
 # used by both framework-wifi and wifi-service
 rule android.content.pm.BaseParceledListSlice* android.x.net.wifi.util.BaseParceledListSlice@1
 rule android.content.pm.ParceledListSlice* android.x.net.wifi.util.ParceledListSlice@1
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5e60b26..e1acaf8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1353,7 +1353,7 @@
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
-                            mContext.getFeatureId());
+                            mContext.getAttributionTag());
             if (parceledList == null) {
                 return Collections.emptyList();
             }
@@ -1370,7 +1370,7 @@
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
-                            mContext.getFeatureId());
+                            mContext.getAttributionTag());
             if (parceledList == null) {
                 return Collections.emptyList();
             }
@@ -1899,7 +1899,7 @@
             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
         try {
             return mService.addNetworkSuggestions(
-                    networkSuggestions, mContext.getOpPackageName(), mContext.getFeatureId());
+                    networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2681,8 +2681,8 @@
     public boolean startScan(WorkSource workSource) {
         try {
             String packageName = mContext.getOpPackageName();
-            String featureId = mContext.getFeatureId();
-            return mService.startScan(packageName, featureId);
+            String attributionTag = mContext.getAttributionTag();
+            return mService.startScan(packageName, attributionTag);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2714,7 +2714,7 @@
     public WifiInfo getConnectionInfo() {
         try {
             return mService.getConnectionInfo(mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2729,7 +2729,7 @@
     public List<ScanResult> getScanResults() {
         try {
             return mService.getScanResults(mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2760,7 +2760,7 @@
         try {
             return mService.getMatchingScanResults(
                     networkSuggestionsToMatch, scanResults,
-                    mContext.getOpPackageName(), mContext.getFeatureId());
+                    mContext.getOpPackageName(), mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3199,7 +3199,7 @@
                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
             try {
                 String packageName = mContext.getOpPackageName();
-                String featureId = mContext.getFeatureId();
+                String featureId = mContext.getAttributionTag();
                 int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
                         config);
                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
@@ -5891,7 +5891,7 @@
         try {
             mService.registerSuggestionConnectionStatusListener(new Binder(),
                     new SuggestionConnectionStatusListenerProxy(executor, listener),
-                    listener.hashCode(), mContext.getOpPackageName(), mContext.getFeatureId());
+                    listener.hashCode(), mContext.getOpPackageName(), mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 6dbb0bd..72ca900 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -545,6 +545,7 @@
                     mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
                             : WifiConfiguration.METERED_OVERRIDE_NONE;
             wifiConfiguration.carrierId = mCarrierId;
+            wifiConfiguration.trusted = !mIsNetworkUntrusted;
             return wifiConfiguration;
         }
 
@@ -684,8 +685,7 @@
                     mIsAppInteractionRequired,
                     mIsUserInteractionRequired,
                     mIsSharedWithUser,
-                    mIsInitialAutojoinEnabled,
-                    mIsNetworkUntrusted);
+                    mIsInitialAutojoinEnabled);
         }
     }
 
@@ -728,13 +728,6 @@
      */
     public final boolean isInitialAutoJoinEnabled;
 
-    /**
-     * Whether this network will be brought up as untrusted (TRUSTED capability bit removed).
-     * @hide
-     */
-    public final boolean isNetworkUntrusted;
-
-
     /** @hide */
     public WifiNetworkSuggestion() {
         this.wifiConfiguration = new WifiConfiguration();
@@ -743,7 +736,6 @@
         this.isUserInteractionRequired = false;
         this.isUserAllowedToManuallyConnect = true;
         this.isInitialAutoJoinEnabled = true;
-        this.isNetworkUntrusted = false;
     }
 
     /** @hide */
@@ -752,8 +744,7 @@
                                  boolean isAppInteractionRequired,
                                  boolean isUserInteractionRequired,
                                  boolean isUserAllowedToManuallyConnect,
-                                 boolean isInitialAutoJoinEnabled,
-                                 boolean isNetworkUntrusted) {
+                                 boolean isInitialAutoJoinEnabled) {
         checkNotNull(networkConfiguration);
         this.wifiConfiguration = networkConfiguration;
         this.passpointConfiguration = passpointConfiguration;
@@ -762,7 +753,6 @@
         this.isUserInteractionRequired = isUserInteractionRequired;
         this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
         this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
-        this.isNetworkUntrusted = isNetworkUntrusted;
     }
 
     public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -775,8 +765,7 @@
                             in.readBoolean(), // isAppInteractionRequired
                             in.readBoolean(), // isUserInteractionRequired
                             in.readBoolean(), // isSharedCredentialWithUser
-                            in.readBoolean(),  // isAutojoinEnabled
-                            in.readBoolean()
+                            in.readBoolean()  // isAutojoinEnabled
                     );
                 }
 
@@ -799,7 +788,6 @@
         dest.writeBoolean(isUserInteractionRequired);
         dest.writeBoolean(isUserAllowedToManuallyConnect);
         dest.writeBoolean(isInitialAutoJoinEnabled);
-        dest.writeBoolean(isNetworkUntrusted);
     }
 
     @Override
@@ -842,7 +830,7 @@
                 .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
                 .append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
                 .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
-                .append(", isUnTrusted=").append(isNetworkUntrusted)
+                .append(", isUnTrusted=").append(!wifiConfiguration.trusted)
                 .append(" ]");
         return sb.toString();
     }
@@ -933,7 +921,7 @@
 
     /** @see Builder#setUntrusted(boolean)  */
     public boolean isUntrusted() {
-        return isNetworkUntrusted;
+        return !wifiConfiguration.trusted;
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 5e48919..d299cdc 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -182,7 +182,7 @@
     public List<Integer> getAvailableChannels(int band) {
         try {
             Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+                    mContext.getAttributionTag());
             List<Integer> channels = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
             return channels == null ? new ArrayList<>() : channels;
         } catch (RemoteException e) {
@@ -963,7 +963,7 @@
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
-        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
         mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
@@ -984,7 +984,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
-        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
         mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
@@ -1001,7 +1001,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
-        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
         Message reply =
                 mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0, 0, scanParams);
         return reply.what == CMD_OP_SUCCEEDED;
@@ -1056,7 +1056,7 @@
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
-        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
         mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
     }
 
@@ -1073,7 +1073,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
-        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
         mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key, scanParams);
     }
 
@@ -1086,7 +1086,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
-        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
         Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0, 0,
                 scanParams);
         if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 2ebaa18..c2ae17c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -267,7 +267,7 @@
 
             try {
                 Binder binder = new Binder();
-                mService.connect(binder, mContext.getOpPackageName(), mContext.getFeatureId(),
+                mService.connect(binder, mContext.getOpPackageName(), mContext.getAttributionTag(),
                         new WifiAwareEventCallbackProxy(this, looper, binder, attachCallback,
                                 identityChangedListener), configRequest,
                         identityChangedListener != null);
@@ -298,7 +298,7 @@
         }
 
         try {
-            mService.publish(mContext.getOpPackageName(), mContext.getFeatureId(), clientId,
+            mService.publish(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
                     publishConfig,
                     new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
                             clientId));
@@ -336,7 +336,7 @@
         }
 
         try {
-            mService.subscribe(mContext.getOpPackageName(), mContext.getFeatureId(), clientId,
+            mService.subscribe(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
                     subscribeConfig,
                     new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
                             clientId));
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 65e8b3d..fa806e7 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -1037,18 +1037,7 @@
      * @return a Unique identifier for a Credential object
      */
     public int getUniqueId() {
-        int usedCredential;
-
-        // Initialize usedCredential based on the credential type of the profile
-        if (mUserCredential != null) {
-            usedCredential = 0;
-        } else if (mCertCredential != null) {
-            usedCredential = 1;
-        } else {
-            usedCredential = 2;
-        }
-
-        return Objects.hash(usedCredential, mRealm);
+        return Objects.hash(mUserCredential, mCertCredential, mSimCredential, mRealm);
     }
 
     @Override
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index a310ff6..724ccf0 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1180,7 +1180,7 @@
                 == AsyncChannel.STATUS_SUCCESSFUL) {
             Bundle bundle = new Bundle();
             bundle.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
-            bundle.putString(CALLING_FEATURE_ID, c.mContext.getFeatureId());
+            bundle.putString(CALLING_FEATURE_ID, c.mContext.getAttributionTag());
             bundle.putBinder(CALLING_BINDER, binder);
             c.mAsyncChannel.sendMessage(UPDATE_CHANNEL_INFO, 0,
                     c.putListener(null), bundle);
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index cb0c5d4..865702a 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -146,8 +146,8 @@
 
         Binder binder = new Binder();
         try {
-            mService.startRanging(binder, mContext.getOpPackageName(), mContext.getFeatureId(),
-                    workSource, request, new IRttCallback.Stub() {
+            mService.startRanging(binder, mContext.getOpPackageName(),
+                    mContext.getAttributionTag(), workSource, request, new IRttCallback.Stub() {
                         @Override
                         public void onRangingFailure(int status) throws RemoteException {
                             clearCallingIdentity();
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 51bf738..01b2a8d 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -532,7 +532,7 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
-                configuration, null, false, true, true, true, false);
+                configuration, null, false, true, true, true);
 
         Parcel parcelW = Parcel.obtain();
         suggestion.writeToParcel(parcelW, 0);
@@ -603,14 +603,14 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, true, false, true, true, false);
+                new WifiNetworkSuggestion(configuration, null, true, false, true, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.BSSID = TEST_BSSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, true, true, true, false);
+                new WifiNetworkSuggestion(configuration1, null, false, true, true, true);
 
         assertEquals(suggestion, suggestion1);
         assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -626,13 +626,13 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, true, true, false);
+                new WifiNetworkSuggestion(configuration, null, false, false, true, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID_1;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, true, true, false);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -648,13 +648,13 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null,  false, false, true, true, false);
+                new WifiNetworkSuggestion(configuration, null,  false, false, true, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, true, true, false);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -669,13 +669,13 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, true, true, false);
+                new WifiNetworkSuggestion(configuration, null, false, false, true, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, true, true, false);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -770,7 +770,7 @@
                 .setWpa2Passphrase(TEST_PRESHARED_KEY)
                 .setUntrusted(true)
                 .build();
-        assertTrue(suggestion.isNetworkUntrusted);
+        assertTrue(suggestion.isUntrusted());
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
     }
 
@@ -786,7 +786,7 @@
                 .setPasspointConfig(passpointConfiguration)
                 .setUntrusted(true)
                 .build();
-        assertTrue(suggestion.isNetworkUntrusted);
+        assertTrue(suggestion.isUntrusted());
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
     }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index 0cc76b6..4881200 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -267,7 +267,7 @@
         assertNull(messageBundle.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY));
         assertEquals(mContext.getOpPackageName(),
                 messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
-        assertEquals(mContext.getFeatureId(),
+        assertEquals(mContext.getAttributionTag(),
                 messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
 
     }
@@ -297,7 +297,7 @@
         Bundle messageBundle = (Bundle) message.obj;
         assertEquals(mContext.getOpPackageName(),
                 messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
-        assertEquals(mContext.getFeatureId(),
+        assertEquals(mContext.getAttributionTag(),
                 messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
     }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index c682582..829d8f0 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.net.wifi.EAPConstants;
@@ -551,4 +552,68 @@
     public void validateTwoCertificateDifferent() {
         assertFalse(Credential.isX509CertificateEquals(FakeKeys.CA_CERT0, FakeKeys.CA_CERT1));
     }
+
+    /**
+     * Verify that unique identifiers are the same for objects with the same credentials
+     */
+    @Test
+    public void testUniqueIdSameCredentialTypes() throws Exception {
+        assertEquals(createCredentialWithSimCredential().getUniqueId(),
+                createCredentialWithSimCredential().getUniqueId());
+        assertEquals(createCredentialWithCertificateCredential().getUniqueId(),
+                createCredentialWithCertificateCredential().getUniqueId());
+        assertEquals(createCredentialWithUserCredential().getUniqueId(),
+                createCredentialWithUserCredential().getUniqueId());
+    }
+
+    /**
+     * Verify that unique identifiers are different for each credential
+     */
+    @Test
+    public void testUniqueIdDifferentForDifferentCredentialTypes() throws Exception {
+        Credential simCred = createCredentialWithSimCredential();
+        Credential certCred = createCredentialWithCertificateCredential();
+        Credential userCred = createCredentialWithUserCredential();
+
+        assertNotEquals(simCred.getUniqueId(), userCred.getUniqueId());
+        assertNotEquals(simCred.getUniqueId(), certCred.getUniqueId());
+        assertNotEquals(certCred.getUniqueId(), userCred.getUniqueId());
+    }
+
+    /**
+     * Verify that unique identifiers are different for a credential with different values
+     */
+    @Test
+    public void testUniqueIdDifferentForSimCredentialsWithDifferentValues() throws Exception {
+        Credential simCred1 = createCredentialWithSimCredential();
+        Credential simCred2 = createCredentialWithSimCredential();
+        simCred2.getSimCredential().setImsi("567890*");
+
+        assertNotEquals(simCred1.getUniqueId(), simCred2.getUniqueId());
+    }
+
+    /**
+     * Verify that unique identifiers are different for a credential with different values
+     */
+    @Test
+    public void testUniqueIdDifferentForUserCredentialsWithDifferentValues() throws Exception {
+        Credential userCred1 = createCredentialWithUserCredential();
+        Credential userCred2 = createCredentialWithUserCredential();
+        userCred2.getUserCredential().setUsername("anotheruser");
+
+        assertNotEquals(userCred1.getUniqueId(), userCred2.getUniqueId());
+    }
+
+    /**
+     * Verify that unique identifiers are different for a credential with different values
+     */
+    @Test
+    public void testUniqueIdDifferentForCertCredentialsWithDifferentValues() throws Exception {
+        Credential certCred1 = createCredentialWithCertificateCredential();
+        Credential certCred2 = createCredentialWithCertificateCredential();
+        certCred2.getCertCredential().setCertSha256Fingerprint(
+                MessageDigest.getInstance("SHA-256").digest(FakeKeys.CA_CERT0.getEncoded()));
+
+        assertNotEquals(certCred1.getUniqueId(), certCred2.getUniqueId());
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index a9dcde0..e6eae416 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -71,7 +71,7 @@
         mMockLooperExecutor = mMockLooper.getNewExecutor();
 
         when(mockContext.getOpPackageName()).thenReturn(packageName);
-        when(mockContext.getFeatureId()).thenReturn(featureId);
+        when(mockContext.getAttributionTag()).thenReturn(featureId);
     }
 
     /**