Merge "Include blob sizes in blob_store service dump." into rvc-dev
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 15a2f22..8a0f660 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -88,27 +88,4 @@
         "com.android.os.statsd",
         "test_com.android.os.statsd",
     ],
-}
-
-android_test {
-    name: "FrameworkStatsdTest",
-    platform_apis: true,
-    srcs: [
-        // TODO(b/147705194): Use framework-statsd as a lib dependency instead.
-        ":framework-statsd-sources",
-        "test/**/*.java",
-    ],
-    manifest: "test/AndroidManifest.xml",
-    static_libs: [
-        "androidx.test.rules",
-        "truth-prebuilt",
-    ],
-    libs: [
-        "android.test.runner.stubs",
-        "android.test.base.stubs",
-    ],
-    test_suites: [
-        "device-tests",
-    ],
-}
-
+}
\ No newline at end of file
diff --git a/apex/statsd/framework/test/Android.bp b/apex/statsd/framework/test/Android.bp
new file mode 100644
index 0000000..b113d59
--- /dev/null
+++ b/apex/statsd/framework/test/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "FrameworkStatsdTest",
+    platform_apis: true,
+    srcs: [
+        // TODO(b/147705194): Use framework-statsd as a lib dependency instead.
+        ":framework-statsd-sources",
+        "**/*.java",
+    ],
+    manifest: "AndroidManifest.xml",
+    static_libs: [
+        "androidx.test.rules",
+        "truth-prebuilt",
+    ],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    test_suites: [
+        "device-tests",
+        "mts",
+    ],
+}
\ No newline at end of file
diff --git a/apex/statsd/framework/test/AndroidTest.xml b/apex/statsd/framework/test/AndroidTest.xml
new file mode 100644
index 0000000..fb51915
--- /dev/null
+++ b/apex/statsd/framework/test/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<configuration description="Runs Tests for Statsd.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworkStatsdTest.apk" />
+        <option name="install-arg" value="-g" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="mts" />
+    <option name="test-tag" value="FrameworkStatsdTest" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.os.statsd.framework.test" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+    </object>
+</configuration>
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 278278f..042983b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -481,6 +481,8 @@
         BlobCommitted blob_committed = 298 [(module) = "framework"];
         BlobLeased blob_leased = 299 [(module) = "framework"];
         BlobOpened blob_opened = 300 [(module) = "framework"];
+        ContactsProviderStatusReported contacts_provider_status_reported = 301;
+        KeystoreKeyEventReported keystore_key_event_reported = 302;
 
         // StatsdStats tracks platform atoms with ids upto 500.
         // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -9907,6 +9909,48 @@
 }
 
 /**
+ * Logs for ContactsProvider general usage.
+ * This is atom ID 301.
+ *
+ * Logged from:
+ *   packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java
+ */
+message ContactsProviderStatusReported {
+    enum ApiType {
+        UNKNOWN_API = 0;
+        QUERY = 1;
+        // INSERT includes insert and bulkInsert, and inserts triggered by applyBatch.
+        INSERT = 2;
+        // UPDATE and DELETE includes update/delete and the ones triggered by applyBatch.
+        UPDATE = 3;
+        DELETE = 4;
+    }
+
+    enum ResultType {
+        UNKNOWN_RESULT = 0;
+        SUCCESS = 1;
+        FAIL = 2;
+        ILLEGAL_ARGUMENT = 3;
+        UNSUPPORTED_OPERATION = 4;
+    }
+
+    enum CallerType {
+        UNSPECIFIED_CALLER_TYPE = 0;
+        CALLER_IS_SYNC_ADAPTER = 1;
+        CALLER_IS_NOT_SYNC_ADAPTER = 2;
+    }
+
+    optional ApiType api_type = 1;
+    // Defined in
+    // packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java
+    optional int32 uri_type = 2;
+    optional CallerType caller_type = 3;
+    optional ResultType result_type = 4;
+    optional int32 result_count = 5;
+    optional int64 latency_micros = 6;
+}
+
+/**
  * Logs when an app is frozen or unfrozen.
  *
  * Logged from:
@@ -10883,6 +10927,114 @@
     optional int32 connection_count = 6;
 }
 
+/**
+ * Logs: i) creation of different types of cryptographic keys in the keystore,
+ * ii) operations performed using the keys,
+ * iii) attestation of the keys
+ * Logged from: system/security/keystore/key_event_log_handler.cpp
+ */
+message KeystoreKeyEventReported {
+
+    enum Algorithm {
+        /** Asymmetric algorithms. */
+        RSA = 1;
+        // 2 removed, do not reuse.
+        EC = 3;
+        /** Block cipher algorithms */
+        AES = 32;
+        TRIPLE_DES = 33;
+        /** MAC algorithms */
+        HMAC = 128;
+    };
+    /** Algorithm associated with the key */
+    optional Algorithm algorithm = 1;
+
+    /** Size of the key */
+    optional int32 key_size = 2;
+
+    enum KeyOrigin {
+        /** Generated in keymaster.  Should not exist outside the TEE. */
+        GENERATED = 0;
+        /** Derived inside keymaster.  Likely exists off-device. */
+        DERIVED = 1;
+        /** Imported into keymaster.  Existed as cleartext in Android. */
+        IMPORTED = 2;
+        /** Keymaster did not record origin. */
+        UNKNOWN = 3;
+        /** Securely imported into Keymaster. */
+        SECURELY_IMPORTED = 4;
+    };
+    /* Logs whether the key was generated, imported, securely imported, or derived.*/
+    optional KeyOrigin key_origin = 3;
+
+    enum HardwareAuthenticatorType {
+        NONE = 0;
+        PASSWORD = 1;
+        FINGERPRINT = 2;
+        // Additional entries must be powers of 2.
+    };
+    /**
+     * What auth types does this key require? If none,
+     * then no auth required.
+     */
+    optional HardwareAuthenticatorType user_auth_type = 4;
+
+    /**
+     * If user authentication is required, is the requirement time based? If it
+     * is not time based then this field will not be used and the key is per
+     * operation. Per operation keys must be user authenticated on each usage.
+     */
+    optional int32 user_auth_key_timeout_secs = 5;
+
+    /**
+     * padding mode, digest, block_mode and purpose should ideally be repeated
+     * fields. However, since statsd does not support repeated fields in
+     * pushed atoms, they are represented using bitmaps.
+     */
+
+    /** Track which padding mode is being used.*/
+    optional int32 padding_mode_bitmap = 6;
+
+    /** Track which digest is being used. */
+    optional int32 digest_bitmap = 7;
+
+    /** Track what block mode is being used (for encryption). */
+    optional int32 block_mode_bitmap = 8;
+
+    /** Track what purpose is this key serving. */
+    optional int32 purpose_bitmap = 9;
+
+    enum EcCurve {
+        P_224 = 0;
+        P_256 = 1;
+        P_384 = 2;
+        P_521 = 3;
+    };
+    /** Which ec curve was selected if elliptic curve cryptography is in use **/
+    optional EcCurve ec_curve = 10;
+
+    enum KeyBlobUsageRequirements {
+        STANDALONE = 0;
+        REQUIRES_FILE_SYSTEM = 1;
+    };
+    /** Standalone or is a file system required */
+    optional KeyBlobUsageRequirements key_blob_usage_reqs = 11;
+
+    enum Type {
+        key_operation = 0;
+        key_creation = 1;
+        key_attestation = 2;
+    }
+    /** Key creation event, operation event or attestation event? */
+    optional Type type = 12;
+
+    /** Was the key creation, operation, or attestation successful? */
+    optional bool was_successful = 13;
+
+    /** Response code or error code */
+    optional int32 error_code = 14;
+}
+
 // Blob Committer stats
 // Keep in sync between:
 //     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index 23f8ca4..a21eb9b 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -33,6 +33,12 @@
 namespace os {
 namespace statsd {
 
+// These constants must be kept in sync with those in StatsDimensionsValue.java.
+const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
+const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3;
+const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6;
+const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
+
 namespace {
 void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
                   const vector<int>& attributionUids, const vector<string>& attributionTags,
@@ -291,34 +297,76 @@
     }
 }
 
-//TODO(b/149050405) Update this test for StatsDimensionValueParcel
-//TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
-//    HashableDimensionKey dim;
-//
-//    int pos1[] = {1, 1, 1};
-//    int pos2[] = {1, 1, 2};
-//    int pos3[] = {1, 1, 3};
-//    int pos4[] = {2, 0, 0};
-//
-//    Field field1(10, pos1, 2);
-//    Field field2(10, pos2, 2);
-//    Field field3(10, pos3, 2);
-//    Field field4(10, pos4, 0);
-//
-//    Value value1((int32_t)10025);
-//    Value value2("tag");
-//    Value value3((int32_t)987654);
-//    Value value4((int32_t)99999);
-//
-//    dim.addValue(FieldValue(field1, value1));
-//    dim.addValue(FieldValue(field2, value2));
-//    dim.addValue(FieldValue(field3, value3));
-//    dim.addValue(FieldValue(field4, value4));
-//
-//    SubscriberReporter::getStatsDimensionsValue(dim);
-//    // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
-//    // have any read api.
-//}
+void checkAttributionNodeInDimensionsValueParcel(StatsDimensionsValueParcel& attributionNodeParcel,
+                                                 int32_t nodeDepthInAttributionChain,
+                                                 int32_t uid, string tag) {
+    EXPECT_EQ(attributionNodeParcel.field, nodeDepthInAttributionChain /*position at depth 1*/);
+    ASSERT_EQ(attributionNodeParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE);
+    ASSERT_EQ(attributionNodeParcel.tupleValue.size(), 2);
+
+    StatsDimensionsValueParcel uidParcel = attributionNodeParcel.tupleValue[0];
+    EXPECT_EQ(uidParcel.field, 1 /*position at depth 2*/);
+    EXPECT_EQ(uidParcel.valueType, STATS_DIMENSIONS_VALUE_INT_TYPE);
+    EXPECT_EQ(uidParcel.intValue, uid);
+
+    StatsDimensionsValueParcel tagParcel = attributionNodeParcel.tupleValue[1];
+    EXPECT_EQ(tagParcel.field, 2 /*position at depth 2*/);
+    EXPECT_EQ(tagParcel.valueType, STATS_DIMENSIONS_VALUE_STRING_TYPE);
+    EXPECT_EQ(tagParcel.stringValue, tag);
+}
+
+// Test conversion of a HashableDimensionKey into a StatsDimensionValueParcel
+TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
+    int atomId = 10;
+    // First four fields form an attribution chain
+    int pos1[] = {1, 1, 1};
+    int pos2[] = {1, 1, 2};
+    int pos3[] = {1, 2, 1};
+    int pos4[] = {1, 2, 2};
+    int pos5[] = {2, 1, 1};
+
+    Field field1(atomId, pos1, /*depth=*/2);
+    Field field2(atomId, pos2, /*depth=*/2);
+    Field field3(atomId, pos3, /*depth=*/2);
+    Field field4(atomId, pos4, /*depth=*/2);
+    Field field5(atomId, pos5, /*depth=*/0);
+
+    Value value1((int32_t)1);
+    Value value2("string2");
+    Value value3((int32_t)3);
+    Value value4("string4");
+    Value value5((float)5.0);
+
+    HashableDimensionKey dimensionKey;
+    dimensionKey.addValue(FieldValue(field1, value1));
+    dimensionKey.addValue(FieldValue(field2, value2));
+    dimensionKey.addValue(FieldValue(field3, value3));
+    dimensionKey.addValue(FieldValue(field4, value4));
+    dimensionKey.addValue(FieldValue(field5, value5));
+
+    StatsDimensionsValueParcel rootParcel = dimensionKey.toStatsDimensionsValueParcel();
+    EXPECT_EQ(rootParcel.field, atomId);
+    ASSERT_EQ(rootParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE);
+    ASSERT_EQ(rootParcel.tupleValue.size(), 2);
+
+    // Check that attribution chain is populated correctly
+    StatsDimensionsValueParcel attributionChainParcel = rootParcel.tupleValue[0];
+    EXPECT_EQ(attributionChainParcel.field, 1 /*position at depth 0*/);
+    ASSERT_EQ(attributionChainParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE);
+    ASSERT_EQ(attributionChainParcel.tupleValue.size(), 2);
+    checkAttributionNodeInDimensionsValueParcel(attributionChainParcel.tupleValue[0],
+                                                /*nodeDepthInAttributionChain=*/1,
+                                                value1.int_value, value2.str_value);
+    checkAttributionNodeInDimensionsValueParcel(attributionChainParcel.tupleValue[1],
+                                                /*nodeDepthInAttributionChain=*/2,
+                                                value3.int_value, value4.str_value);
+
+    // Check that the float is populated correctly
+    StatsDimensionsValueParcel floatParcel = rootParcel.tupleValue[1];
+    EXPECT_EQ(floatParcel.field, 2 /*position at depth 0*/);
+    EXPECT_EQ(floatParcel.valueType, STATS_DIMENSIONS_VALUE_FLOAT_TYPE);
+    EXPECT_EQ(floatParcel.floatValue, value5.float_value);
+}
 
 TEST(AtomMatcherTest, TestWriteDimensionToProto) {
     HashableDimensionKey dim;
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 24be45c..8e68741 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -51,13 +51,6 @@
         return s == null ? null : Pattern.compile(s);
     }
 
-    static boolean matches(ScanFilter filter, BluetoothDevice device) {
-        boolean result = matchesAddress(filter.getDeviceAddress(), device)
-                && matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device);
-        if (DEBUG) debugLogMatchResult(result, device, filter);
-        return result;
-    }
-
     static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
         final boolean result = deviceAddress == null
                 || (device != null && deviceAddress.equals(device.getAddress()));
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index dccfb03..8c071fe 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -37,7 +37,6 @@
 
 import com.android.internal.util.BitUtils;
 import com.android.internal.util.ObjectUtils;
-import com.android.internal.util.Preconditions;
 
 import libcore.util.HexEncoding;
 
@@ -166,21 +165,18 @@
 
     /** @hide */
     @Override
-    public boolean matches(ScanResult device) {
-        boolean result = matches(device.getDevice())
+    public boolean matches(ScanResult scanResult) {
+        BluetoothDevice device = scanResult.getDevice();
+        boolean result = getScanFilter().matches(scanResult)
+                && BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device)
                 && (mRawDataFilter == null
-                    || BitUtils.maskedEquals(device.getScanRecord().getBytes(),
+                    || BitUtils.maskedEquals(scanResult.getScanRecord().getBytes(),
                             mRawDataFilter, mRawDataFilterMask));
         if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device +
                 ") -> " + result);
         return result;
     }
 
-    private boolean matches(BluetoothDevice device) {
-        return BluetoothDeviceFilterUtils.matches(getScanFilter(), device)
-                && BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device);
-    }
-
     /** @hide */
     @Override
     public int getMediumType() {
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 570cc2c..2d2dda0 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -26,6 +26,8 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
 import android.util.Slog;
 
 /**
@@ -82,6 +84,9 @@
      *
      * <p>Types may combined via bitwise OR into a single integer representing multiple
      * authenticators (e.g. <code>DEVICE_CREDENTIAL | BIOMETRIC_WEAK</code>).
+     *
+     * @see #canAuthenticate(int)
+     * @see BiometricPrompt.Builder#setAllowedAuthenticators(int)
      */
     public interface Authenticators {
         /**
@@ -118,6 +123,10 @@
          * Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
          * requirements for <strong>Tier 3</strong> (formerly <strong>Strong</strong>), as defined
          * by the Android CDD.
+         *
+         * <p>This corresponds to {@link KeyProperties#AUTH_BIOMETRIC_STRONG} during key generation.
+         *
+         * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
          */
         int BIOMETRIC_STRONG = 0x000F;
 
@@ -156,6 +165,11 @@
          * The non-biometric credential used to secure the device (i.e., PIN, pattern, or password).
          * This should typically only be used in combination with a biometric auth type, such as
          * {@link #BIOMETRIC_WEAK}.
+         *
+         * <p>This corresponds to {@link KeyProperties#AUTH_DEVICE_CREDENTIAL} during key
+         * generation.
+         *
+         * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
          */
         int DEVICE_CREDENTIAL = 1 << 15;
     }
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 5af7cef..74cacea 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -36,6 +36,8 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.security.identity.IdentityCredential;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -371,6 +373,14 @@
          * button on the prompt, making it an error to also call
          * {@link #setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
          *
+         * <p>If unlocking cryptographic operation(s), it is the application's responsibility to
+         * request authentication with the proper set of authenticators (e.g. match the
+         * authenticators specified during key generation).
+         *
+         * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
+         * @see KeyProperties#AUTH_BIOMETRIC_STRONG
+         * @see KeyProperties#AUTH_DEVICE_CREDENTIAL
+         *
          * @param authenticators A bit field representing all valid authenticator types that may be
          *                       invoked by the prompt.
          * @return This builder.
@@ -606,8 +616,24 @@
     }
 
     /**
-     * A wrapper class for the crypto objects supported by BiometricPrompt. Currently the framework
-     * supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+     * A wrapper class for the cryptographic operations supported by BiometricPrompt.
+     *
+     * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac}, and
+     * {@link IdentityCredential}.
+     *
+     * <p>Cryptographic operations in Android can be split into two categories: auth-per-use and
+     * time-based. This is specified during key creation via the timeout parameter of the
+     * {@link KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)} API.
+     *
+     * <p>CryptoObjects are used to unlock auth-per-use keys via
+     * {@link BiometricPrompt#authenticate(CryptoObject, CancellationSignal, Executor,
+     * AuthenticationCallback)}, whereas time-based keys are unlocked for their specified duration
+     * any time the user authenticates with the specified authenticators (e.g. unlocking keyguard).
+     * If a time-based key is not available for use (i.e. none of the allowed authenticators have
+     * been unlocked recently), applications can prompt the user to authenticate via
+     * {@link BiometricPrompt#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
+     *
+     * @see Builder#setAllowedAuthenticators(int)
      */
     public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
         public CryptoObject(@NonNull Signature signature) {
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index a3fd60e..004f844 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -900,9 +900,17 @@
      * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
      * reset to Process.INVALID_UID unless all the following conditions are met:
      *
+     * <p>The caller is the network owner, AND one of the following sets of requirements is met:
+     *
      * <ol>
-     *   <li>The destination app is the network owner
-     *   <li>The destination app has the ACCESS_FINE_LOCATION permission granted
+     *   <li>The described Network is a VPN
+     * </ol>
+     *
+     * <p>OR:
+     *
+     * <ol>
+     *   <li>The calling app is the network owner
+     *   <li>The calling app has the ACCESS_FINE_LOCATION permission granted
      *   <li>The user's location toggle is on
      * </ol>
      *
@@ -928,7 +936,16 @@
     /**
      * Retrieves the UID of the app that owns this network.
      *
-     * <p>For user privacy reasons, this field will only be populated if:
+     * <p>For user privacy reasons, this field will only be populated if the following conditions
+     * are met:
+     *
+     * <p>The caller is the network owner, AND one of the following sets of requirements is met:
+     *
+     * <ol>
+     *   <li>The described Network is a VPN
+     * </ol>
+     *
+     * <p>OR:
      *
      * <ol>
      *   <li>The calling app is the network owner
@@ -936,8 +953,8 @@
      *   <li>The user's location toggle is on
      * </ol>
      *
-     * Instances of NetworkCapabilities sent to apps without the appropriate permissions will
-     * have this field cleared out.
+     * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
+     * this field cleared out.
      */
     public int getOwnerUid() {
         return mOwnerUid;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index e550f85..9876076 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -26,7 +26,6 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Pair;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -554,15 +553,45 @@
     }
 
     /**
-     * A helper class that contains the destination and the gateway in a {@code RouteInfo},
-     * used by {@link ConnectivityService#updateRoutes} or
+     * A helper class that contains the destination, the gateway and the interface in a
+     * {@code RouteInfo}, used by {@link ConnectivityService#updateRoutes} or
      * {@link LinkProperties#addRoute} to calculate the list to be updated.
+     * {@code RouteInfo} objects with different interfaces are treated as different routes because
+     * *usually* on Android different interfaces use different routing tables, and moving a route
+     * to a new routing table never constitutes an update, but is always a remove and an add.
      *
      * @hide
      */
-    public static class RouteKey extends Pair<IpPrefix, InetAddress> {
-        RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway) {
-            super(destination, gateway);
+    public static class RouteKey {
+        @NonNull private final IpPrefix mDestination;
+        @Nullable private final InetAddress mGateway;
+        @Nullable private final String mInterface;
+
+        RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway,
+                @Nullable String iface) {
+            mDestination = destination;
+            mGateway = gateway;
+            mInterface = iface;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof RouteKey)) {
+                return false;
+            }
+            RouteKey p = (RouteKey) o;
+            // No need to do anything special for scoped addresses. Inet6Address#equals does not
+            // consider the scope ID, but the netd route IPCs (e.g., INetd#networkAddRouteParcel)
+            // and the kernel ignore scoped addresses both in the prefix and in the nexthop and only
+            // look at RTA_OIF.
+            return Objects.equals(p.mDestination, mDestination)
+                    && Objects.equals(p.mGateway, mGateway)
+                    && Objects.equals(p.mInterface, mInterface);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mDestination, mGateway, mInterface);
         }
     }
 
@@ -574,7 +603,7 @@
      */
     @NonNull
     public RouteKey getRouteKey() {
-        return new RouteKey(mDestination, mGateway);
+        return new RouteKey(mDestination, mGateway, mInterface);
     }
 
     /**
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index c2234ba..95cc64a 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -564,9 +564,9 @@
         }
 
         void reportResult(@Nullable List<Dataset> inlineSuggestionsData,
-                @Nullable Bundle clientState) {
+                @Nullable Bundle clientState, boolean showingFillWindow) {
             try {
-                mCallback.onSuccess(inlineSuggestionsData, clientState);
+                mCallback.onSuccess(inlineSuggestionsData, clientState, showingFillWindow);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
             }
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 8ba5c17..fc3baf1 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -56,23 +56,24 @@
 
         if (response == null) {
             mProxy.logEvent(AutofillProxy.REPORT_EVENT_NO_RESPONSE);
-            mProxy.reportResult(/* inlineSuggestionsData */ null, /* clientState */ null);
+            mProxy.reportResult(/* inlineSuggestionsData */ null, /* clientState */
+                    null, /* showingFillWindow */ false);
             return;
         }
 
-        List<Dataset> inlineSuggestions = response.getInlineSuggestions();
-        Bundle clientState = response.getClientState();
-        // We need to report result regardless of whether inline suggestions are returned or not.
-        mProxy.reportResult(inlineSuggestions, clientState);
+        final List<Dataset> inlineSuggestions = response.getInlineSuggestions();
+        final Bundle clientState = response.getClientState();
+        final FillWindow fillWindow = response.getFillWindow();
+        boolean showingFillWindow = false;
         if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
             mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE);
-            return;
-        }
-
-        final FillWindow fillWindow = response.getFillWindow();
-        if (fillWindow != null) {
+        } else if (fillWindow != null) {
             fillWindow.show();
+            showingFillWindow = true;
         }
+        // We need to report result regardless of whether inline suggestions are returned or not.
+        mProxy.reportResult(inlineSuggestions, clientState, showingFillWindow);
+
         // TODO(b/123099468): must notify the server so it can update the session state to avoid
         // showing conflicting UIs (for example, if a new request is made to the main autofill
         // service and it now wants to show something).
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index 609e382..4dfdd4d 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -30,7 +30,9 @@
  */
 interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
-    void onSuccess(in @nullable List<Dataset> inlineSuggestionsData, in @nullable Bundle clientState);
+    void onSuccess(in @nullable List<Dataset> inlineSuggestionsData,
+     in @nullable Bundle clientState,
+     boolean showingFillWindow);
     boolean isCompleted();
     void cancel();
 }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index de786be..b4dae56 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -492,12 +492,6 @@
     /** Set of inset types for which an animation was started since last resetting this field */
     private @InsetsType int mLastStartedAnimTypes;
 
-    /** Set of inset types which cannot be controlled by the user animation */
-    private @InsetsType int mLastDisabledUserAnimationInsetsTypes;
-
-    private Runnable mInvokeControllableInsetsChangedListeners =
-            this::invokeControllableInsetsChangedListeners;
-
     public InsetsController(Host host) {
         this(host, (controller, type) -> {
             if (type == ITYPE_IME) {
@@ -612,23 +606,9 @@
 
     private void updateState(InsetsState newState) {
         mState.setDisplayFrame(newState.getDisplayFrame());
-        @InsetsType int disabledUserAnimationTypes = 0;
-        @InsetsType int[] cancelledUserAnimationTypes = {0};
         for (int i = newState.getSourcesCount() - 1; i >= 0; i--) {
             InsetsSource source = newState.sourceAt(i);
-            @InternalInsetsType int internalInsetsType = source.getType();
-            @AnimationType int animationType = getAnimationType(internalInsetsType);
-            if (source.isVisibleFrameEmpty()) {
-                @InsetsType int insetsType = toPublicType(internalInsetsType);
-                // The user animation is not allowed when visible frame is empty.
-                disabledUserAnimationTypes |= insetsType;
-                if (animationType == ANIMATION_TYPE_USER) {
-                    // Existing user animation needs to be cancelled.
-                    animationType = ANIMATION_TYPE_NONE;
-                    cancelledUserAnimationTypes[0] |= insetsType;
-                }
-            }
-            getSourceConsumer(internalInsetsType).updateSource(source, animationType);
+            getSourceConsumer(source.getType()).updateSource(source);
         }
         for (int i = mState.getSourcesCount() - 1; i >= 0; i--) {
             InsetsSource source = mState.sourceAt(i);
@@ -640,27 +620,6 @@
             mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
                     mFrame.right, mFrame.top + mCaptionInsetsHeight));
         }
-
-        updateDisabledUserAnimationTypes(disabledUserAnimationTypes);
-
-        if (cancelledUserAnimationTypes[0] != 0) {
-            mHandler.post(() -> show(cancelledUserAnimationTypes[0]));
-        }
-    }
-
-    private void updateDisabledUserAnimationTypes(@InsetsType int disabledUserAnimationTypes) {
-        @InsetsType int diff = mLastDisabledUserAnimationInsetsTypes ^ disabledUserAnimationTypes;
-        if (diff != 0) {
-            for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
-                InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
-                if (consumer.getControl() != null && (toPublicType(consumer.mType) & diff) != 0) {
-                    mHandler.removeCallbacks(mInvokeControllableInsetsChangedListeners);
-                    mHandler.post(mInvokeControllableInsetsChangedListeners);
-                    break;
-                }
-            }
-            mLastDisabledUserAnimationInsetsTypes = disabledUserAnimationTypes;
-        }
     }
 
     private boolean captionInsetsUnchanged() {
@@ -944,15 +903,6 @@
         boolean imeReady = true;
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
             final InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
-            if (animationType == ANIMATION_TYPE_USER) {
-                final InsetsSource source = mState.peekSource(consumer.getType());
-                if (source != null && source.isVisibleFrameEmpty()) {
-                    if (WARN) Log.w(TAG, String.format(
-                            "collectSourceControls can't run user animation for type: %s",
-                            InsetsState.typeToString(consumer.getType())));
-                    continue;
-                }
-            }
             boolean show = animationType == ANIMATION_TYPE_SHOW
                     || animationType == ANIMATION_TYPE_USER;
             boolean canRun = false;
@@ -1345,8 +1295,7 @@
         @InsetsType int result = 0;
         for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
             InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
-            InsetsSource source = mState.peekSource(consumer.mType);
-            if (consumer.getControl() != null && source != null && !source.isVisibleFrameEmpty()) {
+            if (consumer.getControl() != null) {
                 result |= toPublicType(consumer.mType);
             }
         }
@@ -1357,7 +1306,6 @@
      * @return The types that are now animating due to a listener invoking control/show/hide
      */
     private @InsetsType int invokeControllableInsetsChangedListeners() {
-        mHandler.removeCallbacks(mInvokeControllableInsetsChangedListeners);
         mLastStartedAnimTypes = 0;
         @InsetsType int types = calculateControllableTypes();
         int size = mControllableInsetsChangedListeners.size();
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index c8394d2..15b9a93 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -92,10 +92,6 @@
         return mVisible;
     }
 
-    public boolean isVisibleFrameEmpty() {
-        return mVisibleFrame != null && mVisibleFrame.isEmpty();
-    }
-
     /**
      * Calculates the insets this source will cause to a client window.
      *
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 8d92d7b..5658466 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -18,8 +18,8 @@
 
 import static android.view.InsetsController.ANIMATION_TYPE_NONE;
 import static android.view.InsetsController.AnimationType;
-import static android.view.InsetsController.DEBUG;
 import static android.view.InsetsState.getDefaultVisibility;
+import static android.view.InsetsController.DEBUG;
 import static android.view.InsetsState.toPublicType;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
@@ -275,9 +275,9 @@
     }
 
     @VisibleForTesting(visibility = PACKAGE)
-    public void updateSource(InsetsSource newSource, @AnimationType int animationType) {
+    public void updateSource(InsetsSource newSource) {
         InsetsSource source = mState.peekSource(mType);
-        if (source == null || animationType == ANIMATION_TYPE_NONE
+        if (source == null || mController.getAnimationType(mType) == ANIMATION_TYPE_NONE
                 || source.getFrame().equals(newSource.getFrame())) {
             mPendingFrame = null;
             mPendingVisibleFrame = null;
@@ -286,7 +286,7 @@
         }
 
         // Frame is changing while animating. Keep note of the new frame but keep existing frame
-        // until animation is finished.
+        // until animaition is finished.
         newSource = new InsetsSource(newSource);
         mPendingFrame = new Rect(newSource.getFrame());
         mPendingVisibleFrame = newSource.getVisibleFrame() != null
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6f73e89..e455155 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -230,7 +230,6 @@
      */
     public long mNativeObject;
     private long mNativeHandle;
-    private Throwable mReleaseStack = null;
 
     // TODO: Move this to native.
     private final Object mSizeLock = new Object();
@@ -442,13 +441,6 @@
         }
         mNativeObject = nativeObject;
         mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
-        if (mNativeObject == 0) {
-            if (Build.IS_DEBUGGABLE) {
-                mReleaseStack = new Throwable("assigned zero nativeObject here");
-            }
-        } else {
-            mReleaseStack = null;
-        }
     }
 
     /**
@@ -1024,22 +1016,11 @@
             nativeRelease(mNativeObject);
             mNativeObject = 0;
             mNativeHandle = 0;
-            if (Build.IS_DEBUGGABLE) {
-                mReleaseStack = new Throwable("released here");
-            }
             mCloseGuard.close();
         }
     }
 
     /**
-     * Returns the call stack that assigned mNativeObject to zero.
-     * @hide
-     */
-    public Throwable getReleaseStack() {
-        return mReleaseStack;
-    }
-
-    /**
      * Disconnect any client still connected to the surface.
      * @hide
      */
@@ -1050,11 +1031,8 @@
     }
 
     private void checkNotReleased() {
-        if (mNativeObject == 0) {
-            Log.wtf(TAG, "Invalid " + this + " caused by:", mReleaseStack);
-            throw new NullPointerException(
-                "mNativeObject of " + this + " is null. Have you called release() already?");
-        }
+        if (mNativeObject == 0) throw new NullPointerException(
+                "Invalid " + this + ", mNativeObject is null. Have you called release() already?");
     }
 
     /**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index c098fae..809a9cf 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1620,9 +1620,14 @@
     }
 
     private void updateRelativeZ(Transaction t) {
-        SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl();
-        t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE);
-        t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer);
+        final ViewRootImpl viewRoot = getViewRootImpl();
+        if (viewRoot == null) {
+            // We were just detached.
+            return;
+        }
+        final SurfaceControl viewRootControl = viewRoot.getSurfaceControl();
+        t.setRelativeLayer(mBackgroundControl, viewRootControl, Integer.MIN_VALUE);
+        t.setRelativeLayer(mSurfaceControl, viewRootControl, mSubLayer);
     }
 
     /**
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 6a85de5..8ca218c 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -27,6 +27,7 @@
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnPreDrawListener;
 
 import java.util.function.Consumer;
 
@@ -130,6 +131,16 @@
     @Nullable
     private SurfacePackageUpdater mSurfacePackageUpdater;
 
+    @NonNull
+    private final OnPreDrawListener mDrawListener = new OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            int visibility = InlineContentView.this.isShown() ? VISIBLE : GONE;
+            mSurfaceView.setVisibility(visibility);
+            return true;
+        }
+    };
+
     /**
      * @inheritDoc
      * @hide
@@ -202,6 +213,8 @@
                         }
                     });
         }
+        mSurfaceView.setVisibility(VISIBLE);
+        getViewTreeObserver().addOnPreDrawListener(mDrawListener);
     }
 
     @Override
@@ -211,6 +224,7 @@
         if (mSurfacePackageUpdater != null) {
             mSurfacePackageUpdater.onSurfacePackageReleased();
         }
+        getViewTreeObserver().removeOnPreDrawListener(mDrawListener);
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0a1e3a0..dc4c8fd 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -195,6 +195,7 @@
     private boolean mIsAppPredictorComponentAvailable;
     private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
     private Map<ChooserTarget, ShortcutInfo> mDirectShareShortcutInfoCache;
+    private Map<ComponentName, ComponentName> mChooserTargetComponentNameCache;
 
     public static final int TARGET_TYPE_DEFAULT = 0;
     public static final int TARGET_TYPE_CHOOSER_TARGET = 1;
@@ -511,6 +512,11 @@
                             adapterForUserHandle.addServiceResults(sri.originalTarget,
                                     sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET,
                                     /* directShareShortcutInfoCache */ null, mServiceConnections);
+                            if (!sri.resultTargets.isEmpty() && sri.originalTarget != null) {
+                                mChooserTargetComponentNameCache.put(
+                                        sri.resultTargets.get(0).getComponentName(),
+                                        sri.originalTarget.getResolvedComponentName());
+                            }
                         }
                     }
                     unbindService(sri.connection);
@@ -772,6 +778,7 @@
                 target.getAction()
         );
         mDirectShareShortcutInfoCache = new HashMap<>();
+        mChooserTargetComponentNameCache = new HashMap<>();
     }
 
     @Override
@@ -1063,6 +1070,10 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        ViewPager viewPager = findViewById(R.id.profile_pager);
+        if (shouldShowTabs() && viewPager.isLayoutRtl()) {
+            mMultiProfilePagerAdapter.setupViewPager(viewPager);
+        }
 
         mShouldDisplayLandscape = shouldDisplayLandscape(newConfig.orientation);
         adjustPreviewWidth(newConfig.orientation, null);
@@ -2238,15 +2249,18 @@
         List<AppTargetId> targetIds = new ArrayList<>();
         for (ChooserTargetInfo chooserTargetInfo : surfacedTargetInfo) {
             ChooserTarget chooserTarget = chooserTargetInfo.getChooserTarget();
-            String componentName = chooserTarget.getComponentName().flattenToString();
+            ComponentName componentName = mChooserTargetComponentNameCache.getOrDefault(
+                    chooserTarget.getComponentName(), chooserTarget.getComponentName());
             if (mDirectShareShortcutInfoCache.containsKey(chooserTarget)) {
                 String shortcutId = mDirectShareShortcutInfoCache.get(chooserTarget).getId();
                 targetIds.add(new AppTargetId(
-                        String.format("%s/%s/%s", shortcutId, componentName, SHORTCUT_TARGET)));
+                        String.format("%s/%s/%s", shortcutId, componentName.flattenToString(),
+                                SHORTCUT_TARGET)));
             } else {
                 String titleHash = ChooserUtil.md5(chooserTarget.getTitle().toString());
                 targetIds.add(new AppTargetId(
-                        String.format("%s/%s/%s", titleHash, componentName, CHOOSER_TARGET)));
+                        String.format("%s/%s/%s", titleHash, componentName.flattenToString(),
+                                CHOOSER_TARGET)));
             }
         }
         directShareAppPredictor.notifyLaunchLocationShown(LAUNCH_LOCATION_DIRECT_SHARE, targetIds);
@@ -2268,7 +2282,8 @@
         }
         if (mChooserTargetRankingEnabled && appTarget == null) {
             // Send ChooserTarget sharing info to AppPredictor.
-            ComponentName componentName = chooserTarget.getComponentName();
+            ComponentName componentName = mChooserTargetComponentNameCache.getOrDefault(
+                    chooserTarget.getComponentName(), chooserTarget.getComponentName());
             try {
                 appTarget = new AppTarget.Builder(
                         new AppTargetId(componentName.flattenToString()),
@@ -2796,17 +2811,7 @@
                 || chooserListAdapter.mDisplayList.isEmpty()) {
             chooserListAdapter.notifyDataSetChanged();
         } else {
-            new AsyncTask<Void, Void, Void>() {
-                @Override
-                protected Void doInBackground(Void... voids) {
-                    chooserListAdapter.updateAlphabeticalList();
-                    return null;
-                }
-                @Override
-                protected void onPostExecute(Void aVoid) {
-                    chooserListAdapter.notifyDataSetChanged();
-                }
-            }.execute();
+            chooserListAdapter.updateAlphabeticalList();
         }
 
         // don't support direct share on low ram devices
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index d6ff7b1..0516902 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -275,33 +275,43 @@
     }
 
     void updateAlphabeticalList() {
-        mSortedList.clear();
-        List<DisplayResolveInfo> tempList = new ArrayList<>();
-        tempList.addAll(mDisplayList);
-        tempList.addAll(mCallerTargets);
-        if (mEnableStackedApps) {
-            // Consolidate multiple targets from same app.
-            Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
-            for (DisplayResolveInfo info : tempList) {
-                String packageName = info.getResolvedComponentName().getPackageName();
-                DisplayResolveInfo multiDri = consolidated.get(packageName);
-                if (multiDri == null) {
-                    consolidated.put(packageName, info);
-                } else if (multiDri instanceof MultiDisplayResolveInfo) {
-                    ((MultiDisplayResolveInfo) multiDri).addTarget(info);
-                } else {
-                    // create consolidated target from the single DisplayResolveInfo
-                    MultiDisplayResolveInfo multiDisplayResolveInfo =
-                            new MultiDisplayResolveInfo(packageName, multiDri);
-                    multiDisplayResolveInfo.addTarget(info);
-                    consolidated.put(packageName, multiDisplayResolveInfo);
+        new AsyncTask<Void, Void, List<DisplayResolveInfo>>() {
+            @Override
+            protected List<DisplayResolveInfo> doInBackground(Void... voids) {
+                List<DisplayResolveInfo> allTargets = new ArrayList<>();
+                allTargets.addAll(mDisplayList);
+                allTargets.addAll(mCallerTargets);
+                if (!mEnableStackedApps) {
+                    return allTargets;
                 }
+                // Consolidate multiple targets from same app.
+                Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
+                for (DisplayResolveInfo info : allTargets) {
+                    String packageName = info.getResolvedComponentName().getPackageName();
+                    DisplayResolveInfo multiDri = consolidated.get(packageName);
+                    if (multiDri == null) {
+                        consolidated.put(packageName, info);
+                    } else if (multiDri instanceof MultiDisplayResolveInfo) {
+                        ((MultiDisplayResolveInfo) multiDri).addTarget(info);
+                    } else {
+                        // create consolidated target from the single DisplayResolveInfo
+                        MultiDisplayResolveInfo multiDisplayResolveInfo =
+                            new MultiDisplayResolveInfo(packageName, multiDri);
+                        multiDisplayResolveInfo.addTarget(info);
+                        consolidated.put(packageName, multiDisplayResolveInfo);
+                    }
+                }
+                List<DisplayResolveInfo> groupedTargets = new ArrayList<>();
+                groupedTargets.addAll(consolidated.values());
+                Collections.sort(groupedTargets, new ChooserActivity.AzInfoComparator(mContext));
+                return groupedTargets;
             }
-            mSortedList.addAll(consolidated.values());
-        } else {
-            mSortedList.addAll(tempList);
-        }
-        Collections.sort(mSortedList, new ChooserActivity.AzInfoComparator(mContext));
+            @Override
+            protected void onPostExecute(List<DisplayResolveInfo> newList) {
+                mSortedList = newList;
+                notifyDataSetChanged();
+            }
+        }.execute();
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index daacd45..86c13a0 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1938,7 +1938,7 @@
                 ResolverListAdapter activeListAdapter =
                         mMultiProfilePagerAdapter.getActiveListAdapter();
                 activeListAdapter.notifyDataSetChanged();
-                if (activeListAdapter.getCount() == 0) {
+                if (activeListAdapter.getCount() == 0 && !inactiveListAdapterHasItems()) {
                     // We no longer have any items...  just finish the activity.
                     finish();
                 }
@@ -1948,6 +1948,13 @@
         }
     }
 
+    private boolean inactiveListAdapterHasItems() {
+        if (!shouldShowTabs()) {
+            return false;
+        }
+        return mMultiProfilePagerAdapter.getInactiveListAdapter().getCount() > 0;
+    }
+
     private BroadcastReceiver createWorkProfileStateReceiver() {
         return new BroadcastReceiver() {
             @Override
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 9cdfc2f..478cc18 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -74,12 +74,16 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
+    /**
+     * Sets whether swiping sideways should happen.
+     * <p>Note that swiping is always disabled for RTL layouts (b/159110029 for context).
+     */
     void setSwipingEnabled(boolean swipingEnabled) {
         mSwipingEnabled = swipingEnabled;
     }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return mSwipingEnabled && super.onInterceptTouchEvent(ev);
+        return !isLayoutRtl() && mSwipingEnabled && super.onInterceptTouchEvent(ev);
     }
 }
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index e9d7d05..167d128 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -709,7 +709,7 @@
                 if (DEBUG) {
                     return mDebugName;
                 }
-                return mDelegate.toString() + " wrapped into " + super.toString();
+                return mDelegate + " wrapped into " + super.toString();
             }
 
             @Override
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
index c11b939..69ca992 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
@@ -59,7 +59,7 @@
  * #getProcessCpuUsageDiffed()} result.
  *
  * <p>Thresholding is done in this class, instead of {@link KernelCpuThreadReader}, and instead of
- * WestWorld, because the thresholding should be done after diffing, not before. This is because of
+ * statsd, because the thresholding should be done after diffing, not before. This is because of
  * two issues with thresholding before diffing:
  *
  * <ul>
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 7bfed91..6fe1d81 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy;
 
+import android.graphics.Insets;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
@@ -69,16 +70,14 @@
     private ColorDrawable mNavigationBarColor;
     private boolean mOldFullscreen;
     private boolean mFullscreen;
-    private final Rect mOldSystemInsets = new Rect();
-    private final Rect mOldStableInsets = new Rect();
-    private final Rect mSystemInsets = new Rect();
-    private final Rect mStableInsets = new Rect();
+    private final Rect mOldSystemBarInsets = new Rect();
+    private final Rect mSystemBarInsets = new Rect();
     private final Rect mTmpRect = new Rect();
 
     public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
             Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
             Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
-            boolean fullscreen, Rect systemInsets, Rect stableInsets) {
+            boolean fullscreen, Insets systemBarInsets) {
         setName("ResizeFrame");
 
         mRenderer = renderer;
@@ -95,10 +94,8 @@
         mTargetRect.set(initialBounds);
         mFullscreen = fullscreen;
         mOldFullscreen = fullscreen;
-        mSystemInsets.set(systemInsets);
-        mStableInsets.set(stableInsets);
-        mOldSystemInsets.set(systemInsets);
-        mOldStableInsets.set(stableInsets);
+        mSystemBarInsets.set(systemBarInsets.toRect());
+        mOldSystemBarInsets.set(systemBarInsets.toRect());
 
         // Kick off our draw thread.
         start();
@@ -154,16 +151,13 @@
      *
      * @param newTargetBounds The new target bounds.
      * @param fullscreen Whether the window is currently drawing in fullscreen.
-     * @param systemInsets The current visible system insets for the window.
-     * @param stableInsets The stable insets for the window.
+     * @param systemBarInsets The current visible system insets for the window.
      */
-    public void setTargetRect(Rect newTargetBounds, boolean fullscreen, Rect systemInsets,
-            Rect stableInsets) {
+    public void setTargetRect(Rect newTargetBounds, boolean fullscreen, Rect systemBarInsets) {
         synchronized (this) {
             mFullscreen = fullscreen;
             mTargetRect.set(newTargetBounds);
-            mSystemInsets.set(systemInsets);
-            mStableInsets.set(stableInsets);
+            mSystemBarInsets.set(systemBarInsets);
             // Notify of a bounds change.
             pingRenderLocked(false /* drawImmediate */);
         }
@@ -247,14 +241,12 @@
         mNewTargetRect.set(mTargetRect);
         if (!mNewTargetRect.equals(mOldTargetRect)
                 || mOldFullscreen != mFullscreen
-                || !mStableInsets.equals(mOldStableInsets)
-                || !mSystemInsets.equals(mOldSystemInsets)
+                || !mSystemBarInsets.equals(mOldSystemBarInsets)
                 || mReportNextDraw) {
             mOldFullscreen = mFullscreen;
             mOldTargetRect.set(mNewTargetRect);
-            mOldSystemInsets.set(mSystemInsets);
-            mOldStableInsets.set(mStableInsets);
-            redrawLocked(mNewTargetRect, mFullscreen, mSystemInsets, mStableInsets);
+            mOldSystemBarInsets.set(mSystemBarInsets);
+            redrawLocked(mNewTargetRect, mFullscreen);
         }
     }
 
@@ -304,11 +296,8 @@
      *
      * @param newBounds The window bounds which needs to be drawn.
      * @param fullscreen Whether the window is currently drawing in fullscreen.
-     * @param systemInsets The current visible system insets for the window.
-     * @param stableInsets The stable insets for the window.
      */
-    private void redrawLocked(Rect newBounds, boolean fullscreen, Rect systemInsets,
-            Rect stableInsets) {
+    private void redrawLocked(Rect newBounds, boolean fullscreen) {
 
         // While a configuration change is taking place the view hierarchy might become
         // inaccessible. For that case we remember the previous metrics to avoid flashes.
@@ -355,7 +344,7 @@
         }
         mFrameAndBackdropNode.endRecording();
 
-        drawColorViews(left, top, width, height, fullscreen, systemInsets, stableInsets);
+        drawColorViews(left, top, width, height, fullscreen);
 
         // We need to render the node explicitly
         mRenderer.drawRenderNode(mFrameAndBackdropNode);
@@ -363,14 +352,13 @@
         reportDrawIfNeeded();
     }
 
-    private void drawColorViews(int left, int top, int width, int height,
-            boolean fullscreen, Rect systemInsets, Rect stableInsets) {
+    private void drawColorViews(int left, int top, int width, int height, boolean fullscreen) {
         if (mSystemBarBackgroundNode == null) {
             return;
         }
         RecordingCanvas canvas = mSystemBarBackgroundNode.beginRecording(width, height);
         mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
-        final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
+        final int topInset = mSystemBarInsets.top;
         if (mStatusBarColor != null) {
             mStatusBarColor.setBounds(0, 0, left + width, topInset);
             mStatusBarColor.draw(canvas);
@@ -380,7 +368,7 @@
         // don't want the navigation bar background be moving around when resizing in docked mode.
         // However, we need it for the transitions into/out of docked mode.
         if (mNavigationBarColor != null && fullscreen) {
-            DecorView.getNavigationBarRect(width, height, stableInsets, systemInsets, mTmpRect, 1f);
+            DecorView.getNavigationBarRect(width, height, mSystemBarInsets, mTmpRect, 1f);
             mNavigationBarColor.setBounds(mTmpRect);
             mNavigationBarColor.draw(canvas);
         }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index c6135f2..b12c5e9 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1050,22 +1050,6 @@
         return false;
     }
 
-    public static int getColorViewTopInset(int stableTop, int systemTop) {
-        return Math.min(stableTop, systemTop);
-    }
-
-    public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
-        return Math.min(stableBottom, systemBottom);
-    }
-
-    public static int getColorViewRightInset(int stableRight, int systemRight) {
-        return Math.min(stableRight, systemRight);
-    }
-
-    public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
-        return Math.min(stableLeft, systemLeft);
-    }
-
     public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
         return bottomInset == 0 && rightInset > 0;
     }
@@ -1079,14 +1063,11 @@
                 : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
     }
 
-    public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
-            Rect contentInsets, Rect outRect, float scale) {
-        final int bottomInset =
-                (int) (getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom) * scale);
-        final int leftInset =
-                (int) (getColorViewLeftInset(stableInsets.left, contentInsets.left) * scale);
-        final int rightInset =
-                (int) (getColorViewLeftInset(stableInsets.right, contentInsets.right) * scale);
+    public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect systemBarInsets,
+            Rect outRect, float scale) {
+        final int bottomInset = (int) (systemBarInsets.bottom * scale);
+        final int leftInset = (int) (systemBarInsets.left * scale);
+        final int rightInset = (int) (systemBarInsets.right * scale);
         final int size = getNavBarSize(bottomInset, rightInset, leftInset);
         if (isNavBarToRightEdge(bottomInset, rightInset)) {
             outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
@@ -1113,31 +1094,30 @@
             mLastWindowFlags = attrs.flags;
 
             if (insets != null) {
-                mLastTopInset = getColorViewTopInset(insets.getStableInsetTop(),
-                        insets.getSystemWindowInsetTop());
-                mLastBottomInset = getColorViewBottomInset(insets.getStableInsetBottom(),
-                        insets.getSystemWindowInsetBottom());
-                mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(),
-                        insets.getSystemWindowInsetRight());
-                mLastLeftInset = getColorViewRightInset(insets.getStableInsetLeft(),
-                        insets.getSystemWindowInsetLeft());
+                final Insets systemBarInsets = insets.getInsets(WindowInsets.Type.systemBars());
+                final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
+                        WindowInsets.Type.systemBars());
+                mLastTopInset = systemBarInsets.top;
+                mLastBottomInset = systemBarInsets.bottom;
+                mLastRightInset = systemBarInsets.right;
+                mLastLeftInset = systemBarInsets.left;
 
                 // Don't animate if the presence of stable insets has changed, because that
                 // indicates that the window was either just added and received them for the
                 // first time, or the window size or position has changed.
-                boolean hasTopStableInset = insets.getStableInsetTop() != 0;
+                boolean hasTopStableInset = stableBarInsets.top != 0;
                 disallowAnimate |= (hasTopStableInset != mLastHasTopStableInset);
                 mLastHasTopStableInset = hasTopStableInset;
 
-                boolean hasBottomStableInset = insets.getStableInsetBottom() != 0;
+                boolean hasBottomStableInset = stableBarInsets.bottom != 0;
                 disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset);
                 mLastHasBottomStableInset = hasBottomStableInset;
 
-                boolean hasRightStableInset = insets.getStableInsetRight() != 0;
+                boolean hasRightStableInset = stableBarInsets.right != 0;
                 disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
                 mLastHasRightStableInset = hasRightStableInset;
 
-                boolean hasLeftStableInset = insets.getStableInsetLeft() != 0;
+                boolean hasLeftStableInset = stableBarInsets.left != 0;
                 disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
                 mLastHasLeftStableInset = hasLeftStableInset;
 
@@ -2296,7 +2276,7 @@
     public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
             Rect stableInsets) {
         if (mBackdropFrameRenderer != null) {
-            mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets, stableInsets);
+            mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets);
         }
     }
 
@@ -2314,11 +2294,12 @@
         final ThreadedRenderer renderer = getThreadedRenderer();
         if (renderer != null) {
             loadBackgroundDrawablesIfNeeded();
+            WindowInsets rootInsets = getRootWindowInsets();
             mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
                     initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                     mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
-                    getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
-                    stableInsets);
+                    getCurrentColor(mNavigationColorViewState), fullscreen,
+                    rootInsets.getInsets(WindowInsets.Type.systemBars()));
 
             // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
             // If we want to get the shadow shown while resizing, we would need to elevate a new
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index b64923f..5d4407b 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -233,13 +233,20 @@
             oldVisibility = mImportanceRingView.getVisibility();
             wasGone = oldVisibility == GONE;
             visibility = !mImportantConversation ? GONE : visibility;
-            isGone = visibility == GONE;
-            if (wasGone != isGone) {
+            boolean isRingGone = visibility == GONE;
+            if (wasGone != isRingGone) {
                 // 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.
                 mImportanceRingView.animate().cancel();
                 mImportanceRingView.setVisibility(visibility);
             }
+
+            oldVisibility = mConversationIconBadge.getVisibility();
+            wasGone = oldVisibility == GONE;
+            if (wasGone != isGone) {
+                mConversationIconBadge.animate().cancel();
+                mConversationIconBadge.setVisibility(visibility);
+            }
         });
         // When the small icon is gone, hide the rest of the badge
         mIcon.setOnForceHiddenChangedListener((forceHidden) -> {
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 53272f7..f312d1d 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -42,6 +42,7 @@
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
+import android.widget.TextView;
 
 import com.android.internal.R;
 
@@ -109,6 +110,7 @@
     private ViewGroup mMessagingIconContainer;
     private int mConversationContentStart;
     private int mNonConversationMarginEnd;
+    private int mNotificationTextMarginTop;
 
     public MessagingGroup(@NonNull Context context) {
         super(context);
@@ -148,6 +150,8 @@
                 R.dimen.conversation_content_start);
         mNonConversationMarginEnd = getResources().getDimensionPixelSize(
                 R.dimen.messaging_layout_margin_end);
+        mNotificationTextMarginTop = getResources().getDimensionPixelSize(
+                R.dimen.notification_text_margin_top);
     }
 
     public void updateClipRect() {
@@ -612,7 +616,7 @@
         return 0;
     }
 
-    public View getSenderView() {
+    public TextView getSenderView() {
         return mSenderView;
     }
 
@@ -664,10 +668,14 @@
     public void setSingleLine(boolean singleLine) {
         if (singleLine != mSingleLine) {
             mSingleLine = singleLine;
+            MarginLayoutParams p = (MarginLayoutParams) mMessageContainer.getLayoutParams();
+            p.topMargin = singleLine ? 0 : mNotificationTextMarginTop;
+            mMessageContainer.setLayoutParams(p);
             mContentContainer.setOrientation(
                     singleLine ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
             MarginLayoutParams layoutParams = (MarginLayoutParams) mSenderView.getLayoutParams();
             layoutParams.setMarginEnd(singleLine ? mSenderTextPaddingSingleLine : 0);
+            mSenderView.setSingleLine(singleLine);
             updateMaxDisplayedLines();
             updateClipRect();
             updateSenderVisibility();
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index ac04862..4ee647a 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -300,6 +300,27 @@
         return mMessagingLayout;
     }
 
+    @Override
+    public int getBaseline() {
+        // When placed in a horizontal linear layout (as is the case in a single-line MessageGroup),
+        // align with the last visible child (which is the one that will be displayed in the single-
+        // line group.
+        int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            final View child = getChildAt(i);
+            if (isGone(child)) {
+                continue;
+            }
+            final int childBaseline = child.getBaseline();
+            if (childBaseline == -1) {
+                return -1;
+            }
+            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+            return lp.topMargin + childBaseline;
+        }
+        return super.getBaseline();
+    }
+
     public interface MessagingChild {
         int MEASURED_NORMAL = 0;
         int MEASURED_SHORTENED = 1;
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index a3c455b..b1b39f3 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -47,6 +47,7 @@
 
 #define CHANNEL_INVALID 0
 #define CHANNEL_OUT_DEFAULT 1
+#define CHANNEL_IN_DEFAULT 1
 
 static inline audio_format_t audioFormatToNative(int audioFormat)
 {
@@ -196,12 +197,22 @@
 
 static inline audio_channel_mask_t inChannelMaskToNative(int channelMask)
 {
-    return (audio_channel_mask_t)channelMask;
+    switch (channelMask) {
+        case CHANNEL_IN_DEFAULT:
+            return AUDIO_CHANNEL_NONE;
+        default:
+            return (audio_channel_mask_t)channelMask;
+    }
 }
 
 static inline int inChannelMaskFromNative(audio_channel_mask_t nativeMask)
 {
-    return (int)nativeMask;
+    switch (nativeMask) {
+        case AUDIO_CHANNEL_NONE:
+            return CHANNEL_IN_DEFAULT;
+        default:
+            return (int)nativeMask;
+    }
 }
 
 #endif // ANDROID_MEDIA_AUDIOFORMAT_H
diff --git a/core/proto/android/stats/launcher/launcher.proto b/core/proto/android/stats/launcher/launcher.proto
index dbd0e03..fc177d5 100644
--- a/core/proto/android/stats/launcher/launcher.proto
+++ b/core/proto/android/stats/launcher/launcher.proto
@@ -32,10 +32,12 @@
 }
 
 enum LauncherState {
-    BACKGROUND = 0;
-    HOME = 1;
-    OVERVIEW = 2;
-    ALLAPPS = 3;
+    LAUNCHER_STATE_UNSPECIFIED = 0;
+    BACKGROUND = 1;
+    HOME = 2;
+    OVERVIEW = 3;
+    ALLAPPS = 4;
+    UNCHANGED = 5;
 }
 
 message LauncherTarget {
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 3188861..5e3b657 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -37,6 +37,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_weight="1"
+        android:baselineAligned="true"
         android:orientation="vertical">
         <com.android.internal.widget.ImageFloatingTextView
             android:id="@+id/message_name"
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index c2d5013..56e7a27 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1665,7 +1665,7 @@
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Odbij"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Dodirnite neku funkciju da biste počeli da je koristite:"</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Odaberite funkcije koje ćete koristiti sa dugmetom Pristupačnost"</string>
-    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Odaberite funkcije koje ćete koristiti sa tasterom jačine zvuka kao prečicom"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Odaberite funkcije za prečicu tasterom jačine zvuka"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Usluga <xliff:g id="SERVICE_NAME">%s</xliff:g> je isključena"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Izmenite prečice"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Gotovo"</string>
@@ -1673,8 +1673,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boja"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Zadržali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Zadržali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Izaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Odaberite funkciju koja će se koristiti pomoću pokreta za pristupačnost (pomoću dva prsta prevucite nagore od dna ekrana):"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2bdd4f7..8413622 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1687,7 +1687,7 @@
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Адмовіць"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Каб пачаць выкарыстоўваць функцыю, націсніце на яе:"</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Выберыце функцыі, якія будзеце выкарыстоўваць з кнопкай спецыяльных магчымасцей"</string>
-    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Выберыце функцыі, якія будзеце выкарыстоўваць са спалучэннем клавішы гучнасці"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Выберыце функцыі для выкарыстання з клавішай гучнасці"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Сэрвіс \"<xliff:g id="SERVICE_NAME">%s</xliff:g>\" выключаны"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Змяніць ярлыкі"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Гатова"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e18fc11..8e182a2 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1311,7 +1311,7 @@
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración USB"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
-    <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecciona para inhabilitar la depuración inalámbrica."</string>
+    <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Toca para desactivar la depuración inalámbrica."</string>
     <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo de agente de prueba habilitado"</string>
     <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Restablece los ajustes de fábrica para inhabilitar el modo de agente de prueba."</string>
     <string name="console_running_notification_title" msgid="6087888939261635904">"Se ha habilitado la consola en serie"</string>
@@ -1623,8 +1623,8 @@
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
-    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"¿Quieres activar las funciones de accesibilidad?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Al mantener pulsadas ambas teclas de volumen durante unos segundos, se activan las funciones de accesibilidad, que pueden cambiar el funcionamiento del dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Ajustes &gt; Accesibilidad."</string>
+    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"¿Activar funciones de accesibilidad?"</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Al mantener pulsadas las dos teclas de volumen durante unos segundos, se activan las funciones de accesibilidad, que pueden cambiar el funcionamiento del dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Ajustes &gt; Accesibilidad."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"¿Quieres activar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Al mantener pulsadas ambas teclas de volumen durante unos segundos se activa <xliff:g id="SERVICE">%1$s</xliff:g>, una función de accesibilidad. Esta función puede modificar el funcionamiento del dispositivo.\n\nPuedes asignar este acceso directo a otra función en Ajustes &gt; Accesibilidad."</string>
@@ -1642,8 +1642,8 @@
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Permitir"</string>
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Denegar"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toca una función para empezar a usarla:"</string>
-    <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Seleccionar qué funciones usar con el botón Accesibilidad"</string>
-    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Seleccionar qué funciones usar con la tecla de volumen"</string>
+    <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Selecciona qué funciones usar con el botón Accesibilidad"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Selecciona qué funciones usar con la tecla de volumen"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Se ha desactivado <xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Listo"</string>
@@ -1651,8 +1651,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar acceso directo"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> se ha activado."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Al mantener pulsadas las teclas de volumen, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> se ha desactivado."</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Selecciona la función que se utilizará cuando toques el botón Accesibilidad:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Elige la función que se utilizará con el gesto de accesibilidad (deslizar dos dedos hacia arriba desde la parte inferior de la pantalla):"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 56887d8..e7239eb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1624,10 +1624,10 @@
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"Kas lülitada juurdepääsufunktsioonid sisse?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hoidke mõlemat helitugevuse nuppu mõni sekund all, et juurdepääsufunktsioonid sisse lülitada. See võib teie seadme tööviisi muuta.\n\nPraegused funktsioonid:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nValitud funktsioone saab muuta jaotises Seaded &gt; Juurdepääsetavus."</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hoidke juurdepääsufunktsioonide sisselülitamiseks mõlemat helitugevuse klahvi mõni sekund all. See võib teie seadme tööviisi muuta.\n\nPraegused funktsioonid:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nValitud funktsioone saab muuta jaotises Seaded &gt; Juurdepääsetavus."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"Kas lülitada <xliff:g id="SERVICE">%1$s</xliff:g> sisse?"</string>
-    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Kui hoiate mõlemat helitugevuse nuppu mõni sekund all, lülitatakse sisse juurdepääsufunktsioon <xliff:g id="SERVICE">%1$s</xliff:g>. See võib teie seadme tööviisi muuta.\n\nSelle otsetee saab asendada muu otseteega jaotises Seaded &gt; Juurdepääsetavus."</string>
+    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Kui hoiate mõlemat helitugevuse klahvi mõni sekund all, lülitatakse juurdepääsufunktsioon <xliff:g id="SERVICE">%1$s</xliff:g> sisse. See võib teie seadme tööviisi muuta.\n\nSelle otsetee saab asendada muu otseteega jaotises Seaded &gt; Juurdepääsetavus."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Lülita sisse"</string>
     <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Ära lülita sisse"</string>
     <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"SEES"</string>
@@ -1643,7 +1643,7 @@
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Keela"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Puudutage funktsiooni, et selle kasutamist alustada."</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Valige funktsioonid, mida juurdepääsetavuse nupuga kasutada"</string>
-    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Valige funktsioonid, mida helitugevuse nupu otseteega kasutada"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Valige helitugevuse nupu otsetee funktsioonid"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> on välja lülitatud"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muuda otseteid"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Valmis"</string>
@@ -1651,13 +1651,13 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kasuta otseteed"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Värvide ümberpööramine"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Värvide korrigeerimine"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse nuppe hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse nuppe hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Valige, millist funktsiooni kasutada, kui vajutate juurdepääsetavuse nuppu:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Valige, millist funktsiooni juurdepääsetavuse liigutusega (kahe sõrmega ekraanikuval alt üles pühkimine) kasutada:"</string>
     <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Valige, millist funktsiooni juurdepääsetavuse liigutusega (kolme sõrmega ekraanikuval alt üles pühkimine) kasutada:"</string>
-    <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funktsioonide vahel vahetamiseks vajutage pikalt juurdepääsetavuse nuppu."</string>
+    <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funktsioonide vahel vahetamiseks vajutage juurdepääsetavuse nuppu pikalt."</string>
     <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Funktsioonide vahel vahetamiseks pühkige kahe sõrmega üles ja hoidke."</string>
     <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Funktsioonide vahel vahetamiseks pühkige kolme sõrmega üles ja hoidke."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Suurendus"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0890ae1..9f618d5 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -184,7 +184,7 @@
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"किसी अज्ञात तृतीय पक्ष के द्वारा"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"आपकी वर्क प्रोफ़ाइल का व्यवस्थापक करता है"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> के द्वारा"</string>
-    <string name="work_profile_deleted" msgid="5891181538182009328">"वर्क प्रोफ़ाइल हटाई गई"</string>
+    <string name="work_profile_deleted" msgid="5891181538182009328">"वर्क प्रोफ़ाइल मिटाई गई"</string>
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"वर्क प्रोफ़ाइल व्यवस्थापक ऐप्लिकेशन या तो मौजूद नहीं है या वह खराब हो गया है. परिणामस्वरूप, आपकी वर्क प्रोफ़ाइल और उससे जुड़े डेटा को हटा दिया गया है. सहायता के लिए अपने व्यवस्थापक से संपर्क करें."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"आपकी वर्क प्रोफ़ाइल अब इस डिवाइस पर उपलब्‍ध नहीं है"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"कई बार गलत पासवर्ड डाला गया"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 1fb9a62..ec56952 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1841,7 +1841,7 @@
     <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Աշխատանքային օր"</string>
     <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Շաբաթ-կիրակի"</string>
     <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Միջոցառում"</string>
-    <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Քնելիս"</string>
+    <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Քնի ժամանակ"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ն անջատում է որոշ ձայներ"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Սարքում ներքին խնդիր է առաջացել և այն կարող է կրկնվել, մինչև չվերականգնեք գործարանային կարգավորումները:"</string>
     <string name="system_error_manufacturer" msgid="703545241070116315">"Սարքում ներքին խնդիր է առաջացել: Մանրամասների համար կապվեք արտադրողի հետ:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 9fbd73ea..3fb2a77 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -339,7 +339,7 @@
     <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Mengizinkan aplikasi menambahkan pintasan Layar Utama tanpa tindakan dari pengguna."</string>
     <string name="permlab_uninstall_shortcut" msgid="295263654781900390">"meng-uninstal pintasan"</string>
     <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Mengizinkan aplikasi menghapus pintasan Layar Utama tanpa tindakan dari pengguna."</string>
-    <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"ubah rute panggilan keluar"</string>
+    <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"alihkan panggilan keluar"</string>
     <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"Memungkinkan aplikasi melihat nomor yang dihubungi saat melakukan panggilan keluar dengan opsi untuk mengalihkan panggilan ke nomor lain atau membatalkan panggilan sepenuhnya."</string>
     <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"jawab panggilan telepon"</string>
     <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Mengizinkan aplikasi menjawab panggilan telepon masuk."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b6a850d..80e34ef 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -222,7 +222,7 @@
     <string name="reboot_to_update_reboot" msgid="4474726009984452312">"Riavvio in corso…"</string>
     <string name="reboot_to_reset_title" msgid="2226229680017882787">"Ripristino dati di fabbrica"</string>
     <string name="reboot_to_reset_message" msgid="3347690497972074356">"Riavvio in corso…"</string>
-    <string name="shutdown_progress" msgid="5017145516412657345">"Spegnimento..."</string>
+    <string name="shutdown_progress" msgid="5017145516412657345">"Spegnimento…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Il tablet verrà spento."</string>
     <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Il dispositivo Android TV verrà spento."</string>
     <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"L\'orologio verrà spento."</string>
@@ -856,7 +856,7 @@
     <string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"La SIM è bloccata tramite PUK."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta la Guida dell\'utente o contatta il servizio clienti."</string>
     <string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"La SIM è bloccata."</string>
-    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"Sblocco SIM..."</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"Sblocco SIM…"</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Hai digitato la tua password <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
@@ -879,7 +879,7 @@
     <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Accedi"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Password o nome utente non valido."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Hai dimenticato il nome utente o la password?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Verifica..."</string>
+    <string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Verifica…"</string>
     <string name="lockscreen_unlock_label" msgid="4648257878373307582">"Sblocca"</string>
     <string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Audio attivato"</string>
     <string name="lockscreen_sound_off_label" msgid="2331496559245450053">"Audio disattivato"</string>
@@ -1095,7 +1095,7 @@
     <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Impossibile copiare negli appunti"</string>
     <string name="paste" msgid="461843306215520225">"Incolla"</string>
     <string name="paste_as_plain_text" msgid="7664800665823182587">"Incolla come testo normale"</string>
-    <string name="replace" msgid="7842675434546657444">"Sostituisci..."</string>
+    <string name="replace" msgid="7842675434546657444">"Sostituisci…"</string>
     <string name="delete" msgid="1514113991712129054">"Elimina"</string>
     <string name="copyUrl" msgid="6229645005987260230">"Copia URL"</string>
     <string name="selectTextMode" msgid="3225108910999318778">"Seleziona testo"</string>
@@ -1117,7 +1117,7 @@
     <string name="yes" msgid="9069828999585032361">"OK"</string>
     <string name="no" msgid="5122037903299899715">"Annulla"</string>
     <string name="dialog_alert_title" msgid="651856561974090712">"Attenzione"</string>
-    <string name="loading" msgid="3138021523725055037">"Caricamento..."</string>
+    <string name="loading" msgid="3138021523725055037">"Caricamento…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
     <string name="checked" msgid="9179896827054513119">"selezionato"</string>
@@ -1544,7 +1544,7 @@
     <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Mostra tutto"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Scegli attività"</string>
     <string name="share_action_provider_share_with" msgid="1904096863622941880">"Condividi con"</string>
-    <string name="sending" msgid="206925243621664438">"Invio..."</string>
+    <string name="sending" msgid="206925243621664438">"Invio…"</string>
     <string name="launchBrowserDefault" msgid="6328349989932924119">"Avviare l\'applicazione Browser?"</string>
     <string name="SetupCallDefault" msgid="5581740063237175247">"Accettare la chiamata?"</string>
     <string name="activity_resolver_use_always" msgid="5575222334666843269">"Sempre"</string>
@@ -1591,7 +1591,7 @@
     <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"La scheda SIM è disattivata. Inserisci il codice PUK per continuare. Contatta l\'operatore per avere informazioni dettagliate."</string>
     <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Inserisci il codice PIN desiderato"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Conferma il codice PIN desiderato"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Sblocco scheda SIM..."</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Sblocco scheda SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"Codice PIN errato."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"Il PIN deve essere di 4-8 numeri."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"Il codice PUK deve essere di 8 cifre."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 07579ad..9ada437 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1311,7 +1311,7 @@
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB арқылы түзетуді өшіру үшін таңдаңыз."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Сымсыз түзету байланыстырылды"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Сымсыз түзетуді өшіру үшін түртіңіз."</string>
-    <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Сымсыз түзетуді өшіріңіз."</string>
+    <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Сымсыз түзетуді өшіру үшін басыңыз."</string>
     <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сынақ бағдарламасы режимі қосылды"</string>
     <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сынақ бағдарламасы режимін өшіру үшін зауыттық күйіне қайтарыңыз."</string>
     <string name="console_running_notification_title" msgid="6087888939261635904">"Сериялық консоль қосылды"</string>
@@ -1624,7 +1624,7 @@
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Арнайы мүмкіндік төте жолын пайдалану керек пе?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Түймелер тіркесімі қосулы кезде, екі дыбыс түймесін 3 секунд басып тұрсаңыз, \"Арнайы мүмкіндіктер\" функциясы іске қосылады."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"Арнайы мүмкіндіктер іске қосылсын ба?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, арнайы мүмкіндіктер іске қосылады. Бұл – құрылғының жұмысына әсер етуі мүмкін.\n\nФункциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТаңдалған функцияларды \"Параметрлер &gt; Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, арнайы мүмкіндіктер іске қосылады. Бұл – құрылғының жұмысына әсер етуі мүмкін.\n\nҚазіргі функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТаңдалған функцияларды \"Параметрлер &gt; Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"<xliff:g id="SERVICE">%1$s</xliff:g> қосылсын ба?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, <xliff:g id="SERVICE">%1$s</xliff:g> арнайы қызметі іске қосылады. Бұл – құрылғының жүмысына әсер етуі мүмкін.\n\nБұл таңбашаны басқа функцияға \"Параметрлер &gt; Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
@@ -1643,16 +1643,16 @@
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Қабылдамау"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Функцияны пайдалана бастау үшін түртіңіз:"</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"\"Арнайы мүмкіндіктер\" түймесімен қолданылатын функцияларды таңдаңыз"</string>
-    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Дыбыс деңгейі пернелері таңбашасымен қолданылатын функцияларды таңдаңыз"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Дыбыс деңгейі пернелері тіркесімімен қолданылатын функцияларды таңдаңыз"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> қызметі өшірулі."</string>
-    <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Таңбашаларды өзгерту"</string>
+    <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Жылдам пәрмендерді өзгерту"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Дайын"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Төте жолды өшіру"</string>
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Төте жолды пайдалану"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Түстер инверсиясы"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Түсті түзету"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірулі."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дыбыс деңгейі пернелерін басып тұрған соң, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірілді."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"\"Арнайы мүмкіндіктер\" түймесін түрткенде пайдаланатын функцияны таңдаңыз:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Арнайы мүмкіндіктер қимылымен (екі саусақпен экранның төменгі жағынан жоғары қарай сырғытыңыз) пайдаланатын функцияны таңдаңыз:"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0fe5925..7ea8b43 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1624,11 +1624,11 @@
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"접근성 기능을 사용하시겠습니까?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"볼륨 키 2개를 몇 초 동안 길게 누르면 접근성 기능이 사용 설정됩니다. 이렇게 되면 기기 작동 방식이 달라질 수 있습니다.\n\n현재 기능:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n설정 &gt; 접근성에서 선택한 기능을 변경할 수 있습니다."</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"볼륨 키 2개를 몇 초 동안 길게 누르면 접근성 기능이 사용 설정됩니다. 이때 기기 작동 방식이 달라질 수 있습니다.\n\n현재 기능:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n설정 &gt; 접근성에서 선택한 기능을 변경할 수 있습니다."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"<xliff:g id="SERVICE">%1$s</xliff:g>을(를) 사용하시겠습니까?"</string>
     <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"볼륨 키 2개를 몇 초 동안 길게 누르면 <xliff:g id="SERVICE">%1$s</xliff:g> 접근성 기능이 사용 설정됩니다. 이렇게 되면 기기 작동 방식이 달라질 수 있습니다.\n\n설정 &gt; 접근성에서 이 단축키를 다른 기능으로 변경할 수 있습니다."</string>
-    <string name="accessibility_shortcut_on" msgid="5463618449556111344">"사용 설정"</string>
+    <string name="accessibility_shortcut_on" msgid="5463618449556111344">"사용"</string>
     <string name="accessibility_shortcut_off" msgid="3651336255403648739">"사용 안 함"</string>
     <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"사용"</string>
     <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"사용 안함"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index d910fc0..c21a1d7 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -142,7 +142,7 @@
     <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
     <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi ခေါ်ဆိုမှု"</string>
     <string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
-    <string name="wifi_calling_off_summary" msgid="5626710010766902560">"ပိတ်ထားရသည်"</string>
+    <string name="wifi_calling_off_summary" msgid="5626710010766902560">"ပိတ်ထားသည်"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi သုံး၍ ခေါ်ဆိုသည်"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"မိုဘိုင်းကွန်ရက်သုံး၍ ခေါ်ဆိုသည်"</string>
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ကြိုးမဲ့အင်တာနက် သာလျှင်"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 25cc45b9..a36035e 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -175,7 +175,7 @@
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"अति धेरै <xliff:g id="CONTENT_TYPE">%s</xliff:g> मेटाउने प्रयास गरियो।"</string>
     <string name="low_memory" product="tablet" msgid="5557552311566179924">"ट्याब्लेट भण्डारण खाली छैन! ठाउँ खाली गर्नको लागि केही फाइलहरू मेटाउनुहोस्।"</string>
     <string name="low_memory" product="watch" msgid="3479447988234030194">"भण्डारण भरिएको छ हेर्नुहोस्। ठाउँ खाली गर्न केही फाइलहरू मेटाउनुहोस्।"</string>
-    <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV यन्त्रको भण्डारण भरिएको छ। ठाउँ खाली गर्न केही फाइलहरू मेट्नुहोस्।"</string>
+    <string name="low_memory" product="tv" msgid="6663680413790323318">"Android टिभी यन्त्रको भण्डारण भरिएको छ। ठाउँ खाली गर्न केही फाइलहरू मेट्नुहोस्।"</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"फोन भण्डारण भरिएको छ! ठाउँ खाली गर्नको लागि केही फाइलहरू मेटाउनुहोस्।"</string>
     <plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029">
       <item quantity="other">प्रमाणपत्रका अख्तियारीहरूलाई स्थापना गरियो</item>
@@ -206,7 +206,7 @@
     <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"सक्रिय गर्नुहोस्"</string>
     <string name="me" msgid="6207584824693813140">"मलाई"</string>
     <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ट्याब्लेट विकल्पहरू"</string>
-    <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV सम्बन्धी विकल्पहरू"</string>
+    <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android टिभी सम्बन्धी विकल्पहरू"</string>
     <string name="power_dialog" product="default" msgid="1107775420270203046">"फोन विकल्पहरू"</string>
     <string name="silent_mode" msgid="8796112363642579333">"मौन मोड"</string>
     <string name="turn_on_radio" msgid="2961717788170634233">"वायरलेस अन गर्नुहोस्"</string>
@@ -224,7 +224,7 @@
     <string name="reboot_to_reset_message" msgid="3347690497972074356">"पुनःसुरु हुँदै ..."</string>
     <string name="shutdown_progress" msgid="5017145516412657345">"बन्द गर्दै..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"तपाईँको ट्याब्लेट बन्द हुने छ।"</string>
-    <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"तपाईंको Android TV यन्त्र बन्द हुने छ।"</string>
+    <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"तपाईंको Android टिभी यन्त्र बन्द हुने छ।"</string>
     <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"तपाईँको घडी बन्द गरिने छ।"</string>
     <string name="shutdown_confirm" product="default" msgid="136816458966692315">"तपाईँको फोन बन्द हुने छ।"</string>
     <string name="shutdown_confirm_question" msgid="796151167261608447">"के तपाईं बन्द गर्न चाहनुहुन्छ?"</string>
@@ -233,7 +233,7 @@
     <string name="recent_tasks_title" msgid="8183172372995396653">"नयाँ"</string>
     <string name="no_recent_tasks" msgid="9063946524312275906">"कुनै नयाँ एपहरू छैनन्।"</string>
     <string name="global_actions" product="tablet" msgid="4412132498517933867">"ट्याब्लेट विकल्पहरू"</string>
-    <string name="global_actions" product="tv" msgid="3871763739487450369">"Android TV सम्बन्धी विकल्पहरू"</string>
+    <string name="global_actions" product="tv" msgid="3871763739487450369">"Android टिभी सम्बन्धी विकल्पहरू"</string>
     <string name="global_actions" product="default" msgid="6410072189971495460">"फोन विकल्पहरू"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"स्क्रिन बन्द"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"बन्द गर्नुहोस्"</string>
@@ -357,7 +357,7 @@
     <string name="permdesc_sendSms" msgid="6757089798435130769">"एपलाई SMS सन्देशहरू पठाउन अनुमति दिन्छ। यसले अप्रत्यासित चार्जहरूको परिणाम दिन सक्दछ। खराब एपहरूले तपाईंको पुष्टि बिना सन्देशहरू पठाएर तपाईंको पैसा खर्च गराउन सक्दछ।"</string>
     <string name="permlab_readSms" msgid="5164176626258800297">"तपाईंका पाठ सन्देशहरू (SMS वा MMS) पढ्नुहोस्"</string>
     <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"यस अनुप्रयोगले तपाईंको ट्याब्लेटमा भण्डारण गरिएका सबै SMS (पाठ) सन्देशहरू पढ्न सक्छ।"</string>
-    <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"यस अनुप्रयोगले तपाईंको Android TV यन्त्रमा भण्डार गरिएका सबै SMS.(पाठ) सन्देशहरू पढ्न सक्छ।"</string>
+    <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"यस अनुप्रयोगले तपाईंको Android टिभी यन्त्रमा भण्डार गरिएका सबै SMS.(पाठ) सन्देशहरू पढ्न सक्छ।"</string>
     <string name="permdesc_readSms" product="default" msgid="774753371111699782">"यस अनुप्रयोगले तपाईंको फोनमा भण्डारण गरिएका सबै SMS (पाठ) सन्देशहरू पढ्न सक्छ।"</string>
     <string name="permlab_receiveWapPush" msgid="4223747702856929056">"पाठ सन्देशहरू (WAP) प्राप्त गर्नुहोस्"</string>
     <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP सन्देशहरू प्राप्त गर्न र प्रशोधन गर्न एपलाई अनुमति दिन्छ। यो अनुमतिमा मोनिटर गर्ने वा तपाईँलाई पठाइएका सन्देशहरू तपाईँलाई नदेखाई मेट्ने क्षमता समावेश हुन्छ।"</string>
@@ -379,7 +379,7 @@
     <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"यो अनुप्रयोगले पृष्ठभूमिमा डेटा प्रयोग गर्नसक्छ। यसले गर्दा धेरै डेटा प्रयोग हुनसक्छ।"</string>
     <string name="permlab_persistentActivity" msgid="464970041740567970">"एपहरू जहिले पनि चल्ने बनाउनुहोस्"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"यसको आफ्नै मेमोरीमा दृढ भएकोको अंश बनाउनको लागि एपलाई अनुमति दिन्छ। ट्याब्लेटलाई ढिलो गराउँदै गरेका अन्य अनुप्रयोगहरूलाई सीमित मात्रामा यसले मेमोरी उपलब्ध गराउन सक्छ।"</string>
-    <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"एपलाई आफ्ना केही अंशहरू मेमोरीमा स्थायी रूपमा राख्ने अनुमति दिन्छ। यसले गर्दा अन्य अनुप्रयोगहरूका लागि मेमोरीको अभाव हुन सक्ने भएकाले तपाईंको Android TV यन्त्र सुस्त हुन सक्छ।"</string>
+    <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"एपलाई आफ्ना केही अंशहरू मेमोरीमा स्थायी रूपमा राख्ने अनुमति दिन्छ। यसले गर्दा अन्य अनुप्रयोगहरूका लागि मेमोरीको अभाव हुन सक्ने भएकाले तपाईंको Android टिभी यन्त्र सुस्त हुन सक्छ।"</string>
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"एपलाई मेमोरीमा आफैंको निरन्तरको अंश बनाउन अनुमति दिन्छ। यसले फोनलाई ढिला बनाएर अन्य एपहरूमा मेमोरी SIMित गर्न सक्दछन्।"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"अग्रभूमिको सेवा सञ्चालन गर्नुहोस्"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"एपलाई अग्रभूमिका सेवाहरू प्रयोग गर्ने अनुमति दिन्छ।"</string>
@@ -389,35 +389,35 @@
     <string name="permdesc_writeSettings" msgid="8293047411196067188">"प्रणालीका सेटिङ डेटालाई परिवर्तन गर्नको लागि एपलाई अनुमति दिन्छ। खराब एपहरूले सायद तपाईँको प्रणालीको कन्फिगरेसनलाई क्षति पुर्‍याउन सक्छन्।"</string>
     <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"स्टार्टअपमा चलाउनुहोस्"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"आनुप्रयोगलाई प्रणाली बुट प्रक्रिया पूर्ण हुने बितिकै आफैलाई सुरु गर्ने अनुमति दिन्छ। यसले ट्याब्लेट सुरु गर्नमा ढिला गर्न सक्दछ र एपलाई समग्रमा ट्याब्लेट सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
-    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"एपलाई प्रणाली बुट हुने बित्तिकै स्वत: सुरु हुने अनुमति दिन्छ। यसो गर्दा एप सधैँ चलिरहने भएकाले तपाईंको Android TV यन्त्र सुरु हुन बढी समय लाग्नुका साथै यन्त्रको समग्र कार्यसम्पादन सुस्त हुन सक्छ।"</string>
+    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"एपलाई प्रणाली बुट हुने बित्तिकै स्वत: सुरु हुने अनुमति दिन्छ। यसो गर्दा एप सधैँ चलिरहने भएकाले तपाईंको Android टिभी यन्त्र सुरु हुन बढी समय लाग्नुका साथै यन्त्रको समग्र कार्यसम्पादन सुस्त हुन सक्छ।"</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"एपलाई प्रणाली बुट गरी सकेपछि जति सक्दो चाँडो आफैंमा सुरु गर्न अनुमति दिन्छ। यसले फोन सुरु गर्नमा ढिला गर्न सक्दछ र अनप्रयोगलाई समग्रमा फोन सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
     <string name="permlab_broadcastSticky" msgid="4552241916400572230">"स्टिकि प्रसारण पठाउनुहोस्"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"औपचारिक प्रसारणलाई पठाउनको लागि एउटा एपलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले ट्याब्लेटलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
-    <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"एपलाई प्रसारण समाप्त भइसकेपछि पनि रहिरहने स्टिकी प्रसारणहरू पठाउने अनुमति दिन्छ। यो सुविधाको अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग हुने भएकाले तपाईंको Android TV यन्त्र सुस्त वा अस्थिर हुन सक्छ।"</string>
+    <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"एपलाई प्रसारण समाप्त भइसकेपछि पनि रहिरहने स्टिकी प्रसारणहरू पठाउने अनुमति दिन्छ। यो सुविधाको अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग हुने भएकाले तपाईंको Android टिभी यन्त्र सुस्त वा अस्थिर हुन सक्छ।"</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"औपचारिक प्रसारणलाई पठाउनको लागि एक एपलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले फोनलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
     <string name="permlab_readContacts" msgid="8776395111787429099">"तपाईँका सम्पर्कहरू पढ्नुहोस्"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"एपलाई तपाईंको ट्याब्लेटमा भण्डार गरिएका सम्पर्क ठेगानाहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको ट्याब्लेटमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
-    <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"एपलाई तपाईंको Android TV यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा पढ्न अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको Android TV यन्त्रमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
+    <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"एपलाई तपाईंको Android टिभी यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा पढ्न अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको Android टिभी यन्त्रमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
     <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"एपलाई तपाईंको फोनमा भण्डार गरिएका सम्पर्क ठेगानाहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। एपहरूले सम्पर्क ठेगानाहरू बनाउने तपाईंको फोनमा भण्डार गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले अनुप्रयोगहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सुरक्षित गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string>
     <string name="permlab_writeContacts" msgid="8919430536404830430">"तपाईँका सम्पर्कहरू परिवर्तन गर्नुहोस्"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"एपलाई तपाईंको ट्याब्लेटमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
-    <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"एपलाई तपाईंको Android TV यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
+    <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"एपलाई तपाईंको Android टिभी यन्त्रमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
     <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"एपलाई तपाईंको फोनमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string>
     <string name="permlab_readCallLog" msgid="1739990210293505948">"कल लग पढ्नुहोस्"</string>
     <string name="permdesc_readCallLog" msgid="8964770895425873433">"यस अनुप्रयोगले तपाईंको फोन सम्पर्कको इतिहास पढ्न सक्छ।"</string>
     <string name="permlab_writeCallLog" msgid="670292975137658895">"कल लग लेख्‍नुहोस्"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"आगमन तथा बहर्गमन डेटासहित तपाईँको ट्याब्लेटको कल लगको परिमार्जन गर्न एपलाई अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईँको कल लग परिमार्जन गर्न वा मेटाउन प्रयोग गर्न सक्छन्।"</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"एपलाई तपाईंको Android TV यन्त्रको आगमन र बहिर्गमन कलसम्बन्धी डेटासहित कल लग परिमार्जन गर्ने अनुमति दिन्छ। हानिकारक एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्छन्।"</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"एपलाई तपाईंको Android टिभी यन्त्रको आगमन र बहिर्गमन कलसम्बन्धी डेटासहित कल लग परिमार्जन गर्ने अनुमति दिन्छ। हानिकारक एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्छन्।"</string>
     <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"एपलाई तपाईंको फोनको आउने र बाहिर जाने कलहरूको बारेको डेटा सहित कल लग परिमार्जन गर्न अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्दछ।"</string>
     <string name="permlab_bodySensors" msgid="3411035315357380862">"शरीरका सेन्सरहरूमा पहुँच गराउनुहोस् (जस्तै हृदय धड्कन निगरानीहरू)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"तपाईँको हृदय गति जस्तो सेंसर बाट डेटा पहुँचको लागि एप अनुमति दिन्छ जसले तपाईँको भौतिक अवस्था अनुगमन गर्छ।"</string>
     <string name="permlab_readCalendar" msgid="6408654259475396200">"पात्रोका कार्यक्रम र विवरणहरू पढ्ने"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"यस अनुप्रयोगले तपाईंको ट्याब्लेटमा भण्डारण गरिएका पात्रो सम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string>
-    <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"यस अनुप्रयोगले तपाईंको Android TV यन्त्रमा भण्डार गरिएका पात्रोसम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string>
+    <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"यस अनुप्रयोगले तपाईंको Android टिभी यन्त्रमा भण्डार गरिएका पात्रोसम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string>
     <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"यस अनुप्रयोगले तपाईंको फोनमा भण्डारण गरिएका पात्रो सम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string>
     <string name="permlab_writeCalendar" msgid="6422137308329578076">"पात्रो घटनाहरू थप्नुहोस् वा परिमार्जन गर्नुहोस् र मालिकको ज्ञान बिना नै पाहुनाहरूलाई इमेल पठाउनुहोस्"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"यस अनुप्रयोगले तपाईंको ट्याब्लेटमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने सन्देशहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
-    <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"यस अनुप्रयोगले तपाईंको Android TV यन्त्रमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरूले पठाएको जस्तै देखिने सन्देशहरू पठाउन वा कार्यक्रमका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
+    <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"यस अनुप्रयोगले तपाईंको Android टिभी यन्त्रमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरूले पठाएको जस्तै देखिने सन्देशहरू पठाउन वा कार्यक्रमका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
     <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"यस अनुप्रयोगले तपाईंको फोनमा पात्रोका कार्यक्रमहरू थप्न, हटाउन वा परिवर्तन गर्न सक्छ। यस अनुप्रयोगले पात्रोका मालिकहरू मार्फत आएको जस्तो लाग्ने सन्देशहरू पठाउन वा तिनीहरूका मालिकहरूलाई सूचित नगरिकन कार्यक्रमहरू परिवर्तन गर्न सक्छ।"</string>
     <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"अधिक स्थान प्रदायक आदेशहरू पहुँच गर्नुहोस्"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"एपलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो एपलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
@@ -462,15 +462,15 @@
     <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"उक्त एपलाई यस यन्त्रको फोन नम्बरहरूमाथि पहुँच राख्न दिनुहोस्।"</string>
     <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"कारको स्क्रिन सक्रिय राख्नुहोस्"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ट्याब्लेटलाई निन्द्रामा जानबाट रोक्नुहोस्"</string>
-    <string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"आफ्नो Android TV यन्त्रलाई शयन अवस्थामा जान नदिनुहोस्"</string>
+    <string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"आफ्नो Android टिभी यन्त्रलाई शयन अवस्थामा जान नदिनुहोस्"</string>
     <string name="permlab_wakeLock" product="default" msgid="569409726861695115">"फोनलाई निदाउनबाट रोक्नुहोस्"</string>
     <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"यो अनुमतिले यस एपलाई कारको स्क्रिन सक्रिय राख्न दिन्छ।"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ट्याब्लेटलाई निस्क्रिय हुनबाट रोक्नको लागि एपलाई अनुमति दिन्छ।"</string>
-    <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"एपलाई तपाईंको Android TV यन्त्रलाई शयन अवस्थामा जानबाट रोक्ने अनुमति दिन्छ।"</string>
+    <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"एपलाई तपाईंको Android टिभी यन्त्रलाई शयन अवस्थामा जानबाट रोक्ने अनुमति दिन्छ।"</string>
     <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"फोनलाई निस्क्रिय हुनबाट रोक्नको लागि एपलाई अनुमति दिन्छ।"</string>
     <string name="permlab_transmitIr" msgid="8077196086358004010">"infrared ट्रान्समिट गर्नुहोस्"</string>
     <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"ट्याबलेटको infrared transmitter प्रयोगको लागि एप अनुमति दिन्छ।"</string>
-    <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"एपलाई तपाईंको Android TV यन्त्रको इन्फ्रारेड ट्रान्समिटर प्रयोग गर्ने अनुमति दिन्छ।"</string>
+    <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"एपलाई तपाईंको Android टिभी यन्त्रको इन्फ्रारेड ट्रान्समिटर प्रयोग गर्ने अनुमति दिन्छ।"</string>
     <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"फोनको infrared transmitter प्रयोगको लागि एप अनुमति दिन्छ।"</string>
     <string name="permlab_setWallpaper" msgid="6959514622698794511">"वालपेपर सेट गर्नुहोस्"</string>
     <string name="permdesc_setWallpaper" msgid="2973996714129021397">"एपलाई प्रणाली वालपेपर सेट गर्न अनुमति दिन्छ।"</string>
@@ -478,11 +478,11 @@
     <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"प्रणाली वालपेपरको आकार सङ्केतहरू मिलाउन एपलाई अनुमति दिन्छ।"</string>
     <string name="permlab_setTimeZone" msgid="7922618798611542432">"समय क्षेत्र सेट गर्नुहोस्"</string>
     <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"एपलाई ट्याब्लेटको समय क्षेत्र परिवर्तन गर्न अनुमति दिन्छ।"</string>
-    <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"एपलाई तपाईंको Android TV यन्त्रको समय क्षेत्र परिवर्तन गर्ने अनुमति दिन्छ।"</string>
+    <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"एपलाई तपाईंको Android टिभी यन्त्रको समय क्षेत्र परिवर्तन गर्ने अनुमति दिन्छ।"</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"एपलाई फोनको समय क्षेत्र परिवर्तन गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_getAccounts" msgid="5304317160463582791">"उपकरणमा खाताहरू भेट्टाउनुहोस्"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"एपलाई ट्याब्लेटद्वारा ज्ञात खाताहरूको सूची पाउन अनुमति दिन्छ। यसले अनुप्रयोगद्वारा तपाईंले स्थापित गर्नुभएको कुनै पनि खाताहरू समावेश गर्न सक्दछ।"</string>
-    <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"एपलाई तपाईंको Android TV यन्त्रले चिनेका खाताहरूको सूची प्राप्त गर्ने अनुमति दिन्छ। उक्त सूचीमा तपाईंले स्थापना गर्नुभएका एपहरूले बनाएका कुनै पनि खाताहरू पर्न सक्छन्।"</string>
+    <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"एपलाई तपाईंको Android टिभी यन्त्रले चिनेका खाताहरूको सूची प्राप्त गर्ने अनुमति दिन्छ। उक्त सूचीमा तपाईंले स्थापना गर्नुभएका एपहरूले बनाएका कुनै पनि खाताहरू पर्न सक्छन्।"</string>
     <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"फोनलाई थाहा भएका खाताहरूको सूची प्राप्त गर्न एपलाई अनुमति दिन्छ। यसले तपाईँले स्थापना गर्नु भएका अनुप्रयोगहरूबाट सृजित कुनै खाताहरू समावेश हुन सक्छ।"</string>
     <string name="permlab_accessNetworkState" msgid="2349126720783633918">"नेटवर्क जडानहरू हेर्नहोस्"</string>
     <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"एपलाई नेटवर्क जडानहरू जस्तै कुन नेटवर्कहरू अवस्थित हुन्छन् र जडित छन् जसले हेर्नलाई अनुमति दिन्छ।"</string>
@@ -498,21 +498,21 @@
     <string name="permdesc_changeWifiState" msgid="7170350070554505384">"एपलाई Wi-Fi पहुँच बिन्दुबाट जडान गर्न र विच्छेदन गर्न र Wi-Fi नेटवर्कहरूको लागि उपकरण कन्फिगरेसनमा परिवर्तनहरू गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"Wi-Fi Multicast स्विकृतिलाई अनुमति दिनुहोस्"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"एपलाई मल्टिकाष्ट ठेगानाहरू प्रयोग गरेर Wi-Fi नेटवर्कमा पठाइएको प्याकेटहरू प्राप्त गर्न अनुमति दिन्छ, केवल तपाईंको ट्याब्लेट मात्र होइन। यसले गैर-मल्टिकाष्ट मोड भन्दा बढी उर्जा प्रयोग गर्दछ।"</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"एपलाई मल्टिकास्ट ठेगानाहरू प्रयोग गरी तपाईंको Android TV यन्त्रमा मात्र नभई कुनै Wi-Fi नेटवर्कमा जोडिएका सबै यन्त्रहरूमा पठाइएका प्याकेटहरू प्राप्त गर्ने अनुमति दिन्छ। यसले गैर मल्टिकास्ट मोडभन्दा बढी पावर खपत गर्छ।"</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"एपलाई मल्टिकास्ट ठेगानाहरू प्रयोग गरी तपाईंको Android टिभी यन्त्रमा मात्र नभई कुनै Wi-Fi नेटवर्कमा जोडिएका सबै यन्त्रहरूमा पठाइएका प्याकेटहरू प्राप्त गर्ने अनुमति दिन्छ। यसले गैर मल्टिकास्ट मोडभन्दा बढी पावर खपत गर्छ।"</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"तपाईँको फोन मात्र होइन, मल्टिकास्ट ठेगानाहरूको प्रयोग गरे Wi-Fi नेटवर्कका सबै उपकरणहरूमा पठाइएका प्याकेटहरू प्राप्त गर्न एपलाई अनुमति दिन्छ। यसले गैर-मल्टिकास्ट मोडभन्दा बढी उर्जा प्रयोग गर्छ।"</string>
     <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ब्लुटुथ सेटिङहरूमा पहुँच गर्नुहोस्"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"स्थानीय ब्लुटुथ ट्याब्लेटलाई कन्फिगर गर्नको लागि र टाढाका उपकरणहरूलाई पत्ता लगाउन र जोड्नको लागि एपलाई अनुमति दिन्छ।"</string>
-    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"एपलाई तपाईंको Android TV यन्त्रको ब्लुटुथ कन्फिगर गर्ने तथा टाढा रहेका यन्त्रहरू पत्ता लगाई ती यन्त्रहरूसँग जोडा बनाउने अनुमति दिन्छ।"</string>
+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"एपलाई तपाईंको Android टिभी यन्त्रको ब्लुटुथ कन्फिगर गर्ने तथा टाढा रहेका यन्त्रहरू पत्ता लगाई ती यन्त्रहरूसँग जोडा बनाउने अनुमति दिन्छ।"</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"एपलाई स्थानीय ब्लुटुथ फोन कन्फिगर गर्न र टाढाका उपकरणहरूसँग खोज गर्न र जोडी गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAXसँग जोड्नुहोस् वा छुटाउनुहोस्"</string>
     <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"एपलाई वाइम्याक्स सक्षम छ कि छैन र जडान भएको कुनै पनि वाइम्याक्स नेटवर्कहरूको बारेमा जानकारी निर्धारिण गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_changeWimaxState" msgid="6223305780806267462">"वाइम्याक्स अवस्था परिवर्तन गर्नुहोस्"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"एपलाई वाइम्याक्स नेटवर्कहरूबाट ट्याब्लेट जडान गर्न र ट्याब्लेट विच्छेदन गर्न अनुमति दिन्छ।"</string>
-    <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"एपलाई तपाईंको Android TV यन्त्र WiMAX नेटवर्कहरूमा जोड्ने वा ती नेटवर्कहरूबाट विच्छेद गर्ने अनुमति दिन्छ।"</string>
+    <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"एपलाई तपाईंको Android टिभी यन्त्र WiMAX नेटवर्कहरूमा जोड्ने वा ती नेटवर्कहरूबाट विच्छेद गर्ने अनुमति दिन्छ।"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"वाइम्याक्स नेटवर्कहरूसँग फोन जोड्न र छुटाउन एपलाई अनुमति दिन्छ।"</string>
     <string name="permlab_bluetooth" msgid="586333280736937209">"ब्लुटुथ उपकरणहरूसँग जोडी मिलाउनुहोस्"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"ट्याब्लेटमा ब्लुटुथको कन्फिगुरेसनलाई हेर्न र बनाउन र जोडी उपकरणहरूसँग जडानहरूलाई स्वीकार गर्न एपलाई अनुमति दिन्छ।"</string>
-    <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"एपलाई तपाईंको Android TV यन्त्रको ब्लुटुथको कन्फिगुरेसन हेर्ने तथा जोडा बनाइएका यन्त्रहरूसँग जोडिने वा ती यन्त्रहरूले पठाएका जोडिने अनुरोध स्वीकार्ने अनुमति दिन्छ।"</string>
+    <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"एपलाई तपाईंको Android टिभी यन्त्रको ब्लुटुथको कन्फिगुरेसन हेर्ने तथा जोडा बनाइएका यन्त्रहरूसँग जोडिने वा ती यन्त्रहरूले पठाएका जोडिने अनुरोध स्वीकार्ने अनुमति दिन्छ।"</string>
     <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"एपलाई फोनमा ब्लुटुथको कन्फिगरेसन हेर्न र जोडी भएका उपकरणहरूसँग जडानहरू बनाउन र स्वीकार गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"NFC भुक्तानी सेवासम्बन्धी रुचाइएको जानकारी"</string>
     <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"यसले एपलाई दर्ता गरिएका सहायता तथा मार्गको गन्तव्य जस्ता रुचाइएका NFC भुक्तानी सेवासम्बन्धी जानकारी प्राप्त गर्न दिन्छ।"</string>
@@ -673,10 +673,10 @@
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"मनिटरको स्क्रिन अनलक गर्ने प्रयासहरू"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने ट्याब्लेट लक गर्नुहोस् वा ट्याब्लेटका सबै डेटा मेट्नुहोस्।"</string>
-    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android TV यन्त्र लक गर्नुहोस् वा यन्त्रमा भएको सम्पूर्ण डेटा मेटाउनुहोस्।"</string>
+    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android टिभी यन्त्र लक गर्नुहोस् वा यन्त्रमा भएको सम्पूर्ण डेटा मेटाउनुहोस्।"</string>
     <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"स्क्रिनअनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने फोन लक गर्नुहोस् वा फोनका सबै डेटा मेट्नुहोस्।"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा ट्याब्लेट लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android TV यन्त्र लक गर्नुहोस् वा यो प्रयोगकर्ताको सम्पूर्ण डेटा मेटाउनुहोस्।"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android टिभी यन्त्र लक गर्नुहोस् वा यो प्रयोगकर्ताको सम्पूर्ण डेटा मेटाउनुहोस्।"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा फोन लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>
     <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रिन लक परिवर्तन गर्ने"</string>
     <string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रिन लक परिवर्तन गर्नुहोस्।"</string>
@@ -684,11 +684,11 @@
     <string name="policydesc_forceLock" msgid="1008844760853899693">"कसरी र कहिले स्क्रिन लक गर्ने नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_wipeData" msgid="1359485247727537311">"सबै डेटा मेट्नुहोस्"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"एउटा फ्याक्ट्रि डेटा रिसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string>
-    <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ्याक्ट्री डेटा रिसेट गरेर चेतावनी नदिइकन आफ्नो Android TV यन्त्रको डेटा मेटाउनुहोस्।"</string>
+    <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ्याक्ट्री डेटा रिसेट गरेर चेतावनी नदिइकन आफ्नो Android टिभी यन्त्रको डेटा मेटाउनुहोस्।"</string>
     <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"एउटा फ्याक्ट्रि डेटा रिसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्न।"</string>
     <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"प्रयोगकर्ता डेटा मेट्नुहोस्"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"चेतावनी बिना यो ट्याब्लेटमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>
-    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"यो Android TV यन्त्रमा भएको यस प्रयोगकर्ताको डेटा चेतावनी नदिइकन मेटाउनुहोस्।"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"यो Android टिभी यन्त्रमा भएको यस प्रयोगकर्ताको डेटा चेतावनी नदिइकन मेटाउनुहोस्।"</string>
     <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"चेतावनी बिना यो फोनमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>
     <string name="policylab_setGlobalProxy" msgid="215332221188670221">"उपकरण विश्वव्यापी प्रोक्सी मिलाउनुहोस्"</string>
     <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"नीति सक्षम हुँदा प्रयोग गरिनको लागि यन्त्र ग्लोवल प्रोक्सी सेट गर्नुहोस्। केवल यन्त्र मालिकले ग्लोवल प्रोक्सी सेट गर्न सक्नुहुन्छ।"</string>
@@ -838,7 +838,7 @@
     <string name="faceunlock_multiple_failures" msgid="681991538434031708">"अत्यधिक मोहडा खोल्ने प्रयासहरू बढी भए।"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"SIM कार्ड छैन"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"ट्याब्लेटमा SIM कार्ड छैन।"</string>
-    <string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"तपाईंको Android TV यन्त्रमा SIM कार्ड छैन।"</string>
+    <string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"तपाईंको Android टिभी यन्त्रमा SIM कार्ड छैन।"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="1408695081255172556">"फोनमा SIM कार्ड छैन।"</string>
     <string name="lockscreen_missing_sim_instructions" msgid="8473601862688263903">"SIM कार्ड घुसाउनुहोस्"</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3664999892038416334">"SIM कार्ड छैन वा पढ्न मिल्दैन। SIM कार्ड हाल्नुहोस्।"</string>
@@ -861,13 +861,13 @@
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"तपाईंले गलत तरिकाले आफ्नो पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक टाइप गर्नुभयो। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"तपाईँले गलत तरिकाले तपाईँको PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक टाइप गर्नु भएको छ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक खिच्नु भएको छ। पछि <xliff:g id="NUMBER_1">%2$d</xliff:g> थप असफल कोसिसहरू, तपाईँको Google साइन इन प्रयोग गरी तपाईँको ट्याब्लेट अनलक गर्न भनिने छ।\n\n  <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फरि प्रयास गर्नुहोस्।"</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो Google खाता मार्फत साइन इन गरेर आफ्नो Android TV यन्त्र अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो Google खाता मार्फत साइन इन गरेर आफ्नो Android टिभी यन्त्र अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"तपाईँले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले तपाईँको अनलक ढाँचालाई कोर्नु भएको छ। पछि <xliff:g id="NUMBER_1">%2$d</xliff:g> अरू धेरै असफल कोसिसहरूपछि, तपाईँलाई तपाईँको फोन Google साइन इन प्रयोग गरेर अनलक गर्नको लागि सोधिने छ। \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा पुनः प्रयास गर्नुहोस्।"</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"तपाईँले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक ट्याब्लेटलाई अनलक गर्नको लागि गलत तरिकाले कोशिस गर्नुभएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> अरू धेरै असफल कोसिसहरूपछि, ट्याब्लेट फ्याट्रि पूर्वनिर्धारितमा रिसेट हुने छ र सबै प्रयोगकर्ता डेटा हराउने छन्।"</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"तपाईंले आफ्नो Android TV यन्त्र <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंको Android TV यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिने छ र प्रयोगकर्ताको सम्पूर्ण डेटा गुम्ने छ।"</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"तपाईंले आफ्नो Android टिभी यन्त्र <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंको Android टिभी यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिने छ र प्रयोगकर्ताको सम्पूर्ण डेटा गुम्ने छ।"</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"तपाईंले गलत तरिकाले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक फोन अनलक गर्ने प्रयत्न गर्नुभयो। <xliff:g id="NUMBER_1">%2$d</xliff:g> बढी असफल प्रयत्नहरू पछि, फोन फ्याक्ट्रि पूर्वनिर्धारितमा रिसेट हुने छ र सबै प्रयोगकर्ता डेटा हराउने छन्।"</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"तपाईँले ट्यब्लेटलाई अनलक गर्न गलत तरिकाले <xliff:g id="NUMBER">%d</xliff:g> पटक प्रयास गर्नु भएको छ। अब ट्याब्लेटलाई पूर्वनिर्धारित कार्यशालामा रिसेट गरिने छ।"</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"तपाईंले आफ्नो Android TV यन्त्र <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। अब तपाईंको Android TV यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिनेछ।"</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"तपाईंले आफ्नो Android टिभी यन्त्र <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। अब तपाईंको Android टिभी यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिनेछ।"</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"तपाईंले गलत तरिकाले फोन <xliff:g id="NUMBER">%d</xliff:g> पटक अनलक गर्ने प्रयत्न गर्नुभयो। अब फोन फ्याक्ट्रि पूर्वनिर्धारितमा रिसेट हुने छ।"</string>
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"ढाँचा बिर्सनु भयो?"</string>
@@ -954,7 +954,7 @@
     <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"ब्राउजरले भ्रमण गरेको सबै URL हरूको इतिहास र ब्राउजरका सबै बुकमार्कहरू पढ्नको लागि एपलाई अनुमति दिन्छ। नोट: यो अनुमतिलाई तेस्रो पक्ष ब्राउजरहरूद्वारा वा वेब ब्राउज गर्ने क्षमताद्वारा बलपूर्वक गराउन सकिँदैन।"</string>
     <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"वेब बुकमार्कहरू र इतिहास लेख्नुहोस्"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"एपलाई तपाईंको ट्याब्लेटमा भण्डार गरिएको ब्राउजरको इतिहास वा बुकमार्कहरू परिमार्जन गर्न अनुमति दिन्छ। यसले एपलाई ब्राजर डेटा मेटाउन वा परिमार्जन गर्न अनुमति दिन सक्दछ। टिप्पणी: यो अनुमति वेब ब्राउज गर्ने क्षमताहरूको साथ तेस्रो-पार्टी ब्राउजर वा अन्य अनुप्रयोगहरूद्वारा लागू गरिएको होइन।"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"एपलाई तपाईंको Android TV यन्त्रमा भण्डार गरिएका ब्राउजरको इतिहास र पुस्तक चिन्हहरू परिमार्जन गर्ने अनुमति दिन्छ। यसले एपलाई ब्राउजरको डेटा मेटाउने वा परिमार्जन गर्ने अनुमति दिन सक्छ। ध्यान दिनुहोस्: तेस्रो पक्षीय ब्राउजर वा वेब ब्राउज गर्ने सुविधा प्रदान गर्ने अन्य एपहरूले यो अनुमति लागू गर्न सक्दैनन्।"</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"एपलाई तपाईंको Android टिभी यन्त्रमा भण्डार गरिएका ब्राउजरको इतिहास र पुस्तक चिन्हहरू परिमार्जन गर्ने अनुमति दिन्छ। यसले एपलाई ब्राउजरको डेटा मेटाउने वा परिमार्जन गर्ने अनुमति दिन सक्छ। ध्यान दिनुहोस्: तेस्रो पक्षीय ब्राउजर वा वेब ब्राउज गर्ने सुविधा प्रदान गर्ने अन्य एपहरूले यो अनुमति लागू गर्न सक्दैनन्।"</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"तपाईँको फोनमा भण्डारण भएको ब्राउजरको इतिहास वा बुकमार्कहरू परिवर्तन गर्नको लागि एपलाई अनुमति दिन्छ। यसले सायद ब्राउजर डेटालाई मेट्न वा परिवर्तन गर्नको लागि एपलाई अनुमति दिन्छ। नोट: वेब ब्राउज गर्ने क्षमतासहितका अन्य एपहरू वा तेस्रो- पक्ष ब्राउजरद्वारा सायद यस अनुमतिलाई लागु गर्न सकिंदैन।"</string>
     <string name="permlab_setAlarm" msgid="1158001610254173567">"एउटा आलर्म सेट गर्नुहोस्"</string>
     <string name="permdesc_setAlarm" msgid="2185033720060109640">"स्थापना गरिएको सङ्केत घडी अनुप्रयोगमा सङ्केत समय मिलाउन एपलाई अनुमति दिन्छ। केही सङ्केत घडी एपहरूले यो सुविधा कार्यान्वयन नगर्न सक्छन्।"</string>
@@ -1555,7 +1555,7 @@
     <string name="activity_resolver_use_once" msgid="948462794469672658">"एक पटक मात्र"</string>
     <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s  कार्य प्रोफाइल समर्थन गर्दैन"</string>
     <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"ट्याब्लेट"</string>
-    <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
+    <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टिभी"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"डक स्पिकरहरू"</string>
     <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
@@ -1613,13 +1613,13 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"तपाईँले तपाईँक पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत टाइप गर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक खिच्नु भएको छ। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"तपाईँले ट्याब्लेटलाई अनलक गर्न गलत तरिकाले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक कोसिस गर्नु भएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> पछि थप असफल प्रयासहरू, ट्याब्लेट पूर्वनिर्धारित कार्यशालामा रिसेट गरिने छ र सबै प्रयोग डेटा हराउने छ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"तपाईंले आफ्नो Android TV यन्त्र <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंको Android TV यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिने छ र प्रयोगकर्ताको सम्पूर्ण डेटा गुम्ने छ।"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"तपाईंले आफ्नो Android टिभी यन्त्र <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंको Android टिभी यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिने छ र प्रयोगकर्ताको सम्पूर्ण डेटा गुम्ने छ।"</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"तपाईँले गलतसँग फोनलाई अनलक गर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक कोसिस गर्नु भयो। <xliff:g id="NUMBER_1">%2$d</xliff:g> पछि थप असफल कोसिसहरू, फोनलाई पूर्वनिर्धारित कार्यशालामा रिसेट गरिने छ र सबै प्रयोग डेटा हराउने छ।"</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"तपाईँले ट्यब्लेटलाई अनलक गर्न गलत तरिकाले <xliff:g id="NUMBER">%d</xliff:g> पटक प्रयास गर्नु भएको छ। अब ट्याब्लेटलाई पूर्वनिर्धारित कार्यशालामा रिसेट गरिने छ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"तपाईंले आफ्नो Android TV यन्त्र <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। अब तपाईंको Android TV यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिनेछ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"तपाईंले आफ्नो Android टिभी यन्त्र <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। अब तपाईंको Android टिभी यन्त्रलाई रिसेट गरेर पूर्वनिर्धारित फ्याक्ट्री सेटिङ लागू गरिनेछ।"</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"तपाईंले गलत तरिकाले फोन <xliff:g id="NUMBER">%d</xliff:g> पटक अनलक गर्ने प्रयत्न गर्नुभयो। अब फोन फ्याक्ट्रि पूर्वनिर्धारितमा रिसेट हुने छ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक कोर्नुभयो। <xliff:g id="NUMBER_1">%2$d</xliff:g> विफल प्रयत्नहरू पछि, तपाईंलाई आफ्नो ट्याब्लेट इमेल खाता प्रयोग गरेर अनलक गर्न सोधिने छ।\n\n फेरि प्रयास गर्नुहोस् <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डहरूमा।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो इमेल खाता प्रयोग गरेर आफ्नो Android TV यन्त्र अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो इमेल खाता प्रयोग गरेर आफ्नो Android टिभी यन्त्र अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
     <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"हटाउनुहोस्"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 269755a..b4b1523 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1665,7 +1665,7 @@
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Одбиј"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Додирните неку функцију да бисте почели да је користите:"</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Одаберите функције које ћете користити са дугметом Приступачност"</string>
-    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Одаберите функције које ћете користити са тастером јачине звука као пречицом"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Одаберите функције за пречицу тастером јачине звука"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Услуга <xliff:g id="SERVICE_NAME">%s</xliff:g> је искључена"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Измените пречице"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Готово"</string>
@@ -1673,8 +1673,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи пречицу"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија боја"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција боја"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Задржали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Задржали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Изаберите функцију која ће се користити када додирнете дугме Приступачност:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Одаберите функцију која ће се користити помоћу покрета за приступачност (помоћу два прста превуците нагоре од дна екрана):"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 45c8e34..b7e8b9a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1417,7 +1417,7 @@
     <string name="forward_intent_to_work" msgid="3620262405636021151">"Ginagamit mo ang app na ito sa iyong profile sa trabaho"</string>
     <string name="input_method_binding_label" msgid="1166731601721983656">"Pamamaraan ng pag-input"</string>
     <string name="sync_binding_label" msgid="469249309424662147">"I-sync"</string>
-    <string name="accessibility_binding_label" msgid="1974602776545801715">"Pagiging Accessible"</string>
+    <string name="accessibility_binding_label" msgid="1974602776545801715">"Accessibility"</string>
     <string name="wallpaper_binding_label" msgid="1197440498000786738">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="3082405680079923708">"Baguhin ang wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2702165274471499713">"Notification listener"</string>
@@ -1621,13 +1621,13 @@
     <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Alisin"</string>
     <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ang sinimulan sa background na serbisyo sa foreground mula sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ay hindi magkakaroon ng pahintulot habang ginagamit sa mga R build sa hinaharap. Pakipuntahan ang go/r-bg-fgs-restriction at maghain ng bugreport."</string>
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Accessibility?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume."</string>
-    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"I-on ang mga feature ng pagiging accessible?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mao-on ang mga feature ng pagiging accessible kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nMga kasalukuyang feature:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuwede mong baguhin ang mga napiling feature sa Mga Setting &gt; Pagiging Accessible."</string>
+    <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"I-on ang mga feature ng accessibility?"</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mao-on ang mga feature ng accessibility kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nMga kasalukuyang feature:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuwede mong baguhin ang mga napiling feature sa Mga Setting &gt; Accessibility."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">"	• <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"I-on ang <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
-    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mao-on ang feature ng pagiging accessible na <xliff:g id="SERVICE">%1$s</xliff:g> kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nPuwede mong palitan ng ibang feature ang shortcut na ito sa Mga Setting &gt; Pagiging Accessible."</string>
+    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mao-on ang feature ng accessibility na <xliff:g id="SERVICE">%1$s</xliff:g> kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nPuwede mong palitan ng ibang feature ang shortcut na ito sa Mga Setting &gt; Accessibility."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"I-on"</string>
     <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Huwag i-on"</string>
     <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"NAKA-ON"</string>
@@ -1651,12 +1651,12 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gamitin ang Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Pag-invert ng Kulay"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Pagwawasto ng Kulay"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Mga volume key na pinipindot nang matagal. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Mga volume key na pinipindot nang matagal. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Pumili ng feature na gagana sa pamamagitan ng pag-tap mo sa button ng accessibility:"</string>
-    <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Pumili ng feature na gagana sa pamamagitan ng galaw ng pagiging accessible (pag-swipe pataas mula sa ibaba ng screen gamit ang dalawang daliri):"</string>
-    <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Pumili ng feature na gagana sa pamamagitan ng galaw ng pagiging accessible (pag-swipe pataas mula sa ibaba ng screen gamit ang tatlong daliri):"</string>
+    <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Pumili ng feature na gagana sa pamamagitan ng galaw ng accessibility (pag-swipe pataas mula sa ibaba ng screen gamit ang dalawang daliri):"</string>
+    <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Pumili ng feature na gagana sa pamamagitan ng galaw ng accessibility (pag-swipe pataas mula sa ibaba ng screen gamit ang tatlong daliri):"</string>
     <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Para magpalipat-lipat sa mga feature, pindutin nang matagal ang button ng accessibility."</string>
     <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Para magpalipat-lipat sa mga feature, mag-swipe pataas gamit ang dalawang daliri at i-hold ito."</string>
     <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Para magpalipat-lipat sa mga feature, mag-swipe pataas gamit ang tatlong daliri at i-hold ito."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bb9ffc0..f3b5a63 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1651,7 +1651,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kısayolu Kullan"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Rengi Ters Çevirme"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Renk Düzeltme"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tutun. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tutun. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Erişilebilirlik düğmesine dokunduğunuzda kullanmak için bir özellik seçin:"</string>
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 1b32725..bf7f339 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -26,11 +26,13 @@
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
 import android.content.Context;
@@ -133,29 +135,37 @@
         InsetsSourceConsumer consumer = new InsetsSourceConsumer(
                 ITYPE_IME, state, null, controller);
 
+        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
+
         InsetsSource source = new InsetsSource(ITYPE_IME);
         source.setFrame(0, 1, 2, 3);
-        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_NONE);
+        consumer.updateSource(new InsetsSource(source));
+
+        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_USER);
 
         // While we're animating, updates are delayed
         source.setFrame(4, 5, 6, 7);
-        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
+        consumer.updateSource(new InsetsSource(source));
         assertEquals(new Rect(0, 1, 2, 3), state.peekSource(ITYPE_IME).getFrame());
 
         // Finish the animation, now the pending frame should be applied
+        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
         assertTrue(consumer.notifyAnimationFinished());
         assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
 
+        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_USER);
+
         // Animating again, updates are delayed
         source.setFrame(8, 9, 10, 11);
-        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
+        consumer.updateSource(new InsetsSource(source));
         assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
 
         // Updating with the current frame triggers a different code path, verify this clears
         // the pending 8, 9, 10, 11 frame:
         source.setFrame(4, 5, 6, 7);
-        consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
+        consumer.updateSource(new InsetsSource(source));
 
+        when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
         assertFalse(consumer.notifyAnimationFinished());
         assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
     }
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index d6542de..e549271 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -129,6 +129,13 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.car.companiondevicesupport",
+    sub_dir: "permissions",
+    src: "com.android.car.companiondevicesupport.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.google.android.car.kitchensink",
     sub_dir: "permissions",
     src: "com.google.android.car.kitchensink.xml",
diff --git a/data/etc/car/com.android.car.companiondevicesupport.xml b/data/etc/car/com.android.car.companiondevicesupport.xml
new file mode 100644
index 0000000..2067bab
--- /dev/null
+++ b/data/etc/car/com.android.car.companiondevicesupport.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.car.companiondevicesupport">
+      <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+      <permission name="android.permission.MANAGE_USERS"/>
+      <permission name="android.permission.PROVIDE_TRUST_AGENT"/>
+      <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
+    </privapp-permissions>
+</permissions>
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index c3993e9..dc9384a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -19,42 +19,9 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.telephony.CarrierConfigManager;
-
-import androidx.annotation.VisibleForTesting;
 
 public class TetherUtil {
-
-    @VisibleForTesting
-    static boolean isEntitlementCheckRequired(Context context) {
-        final CarrierConfigManager configManager = (CarrierConfigManager) context
-             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        if (configManager == null || configManager.getConfig() == null) {
-            // return service default
-            return true;
-        }
-        return configManager.getConfig().getBoolean(CarrierConfigManager
-             .KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
-    }
-
-    public static boolean isProvisioningNeeded(Context context) {
-        // Keep in sync with other usage of config_mobile_hotspot_provision_app.
-        // ConnectivityManager#enforceTetherChangePermission
-        String[] provisionApp = context.getResources().getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
-        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
-                || provisionApp == null) {
-            return false;
-        }
-        // Check carrier config for entitlement checks
-        if (isEntitlementCheckRequired(context) == false) {
-            return false;
-        }
-        return (provisionApp.length == 2);
-    }
-
     public static boolean isTetherAvailable(Context context) {
         final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
         final boolean tetherConfigDisallowed = RestrictedLockUtilsInternal
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
index 0ca7791..df08809 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
@@ -60,13 +60,6 @@
     }
 
     @Test
-    public void isEntitlementCheckRequired_noConfigManager_returnTrue() {
-        doReturn(null).when(mContext).getSystemService(Context.CARRIER_CONFIG_SERVICE);
-
-        assertThat(TetherUtil.isEntitlementCheckRequired(mContext)).isTrue();
-    }
-
-    @Test
     public void isTetherAvailable_supported_configDisallowed_hasUserRestriction_returnTrue() {
         setupIsTetherAvailable(true, true, true);
 
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 67c4458..5f2a946 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -129,7 +129,7 @@
     </style>
 
     <style name="TextAppearance.Keyguard.BottomArea">
-        <item name="android:textSize">16sp</item>
+        <item name="android:textSize">14sp</item>
         <item name="android:maxLines">1</item>
         <item name="android:textColor">?attr/wallpaperTextColor</item>
         <item name="android:shadowColor">@color/keyguard_shadow_color</item>
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
index 7313d54..0f561cb 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
@@ -41,7 +41,8 @@
             android:paddingStart="16dp"
             android:paddingBottom="16dp"
             android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
-            android:maxLines="1"
+            android:maxLines="2"
+            android:ellipsize="end"
             android:text="@string/bubbles_user_education_manage_title"
             android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
 
@@ -52,6 +53,8 @@
             android:paddingStart="16dp"
             android:paddingBottom="24dp"
             android:text="@string/bubbles_user_education_manage"
+            android:maxLines="2"
+            android:ellipsize="end"
             android:fontFamily="@*android:string/config_bodyFontFamily"
             android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
 
diff --git a/packages/SystemUI/res/layout/home_handle.xml b/packages/SystemUI/res/layout/home_handle.xml
index 7c5db10..54a0b9f 100644
--- a/packages/SystemUI/res/layout/home_handle.xml
+++ b/packages/SystemUI/res/layout/home_handle.xml
@@ -21,6 +21,7 @@
     android:layout_width="@dimen/navigation_home_handle_width"
     android:layout_height="match_parent"
     android:layout_weight="0"
+    android:contentDescription="@string/accessibility_home"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
     />
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index b90a371..04de978 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -42,6 +42,17 @@
             android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
             android:accessibilityLiveRegion="polite"/>
 
+        <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+            android:id="@+id/keyguard_indication_enterprise_disclosure"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:paddingStart="@dimen/keyguard_indication_text_padding"
+            android:paddingEnd="@dimen/keyguard_indication_text_padding"
+            android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+            android:alpha=".54"
+            android:visibility="gone"/>
+
     </LinearLayout>
 
     <FrameLayout
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
index 55be77c..a86a469 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
@@ -100,6 +100,7 @@
         mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
 
         setFocusable(true);
+        setClickable(true);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 7f78ddf..6377b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.bubbles;
 
-import static android.app.Notification.FLAG_BUBBLE;
 import static android.os.AsyncTask.Status.FINISHED;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -29,21 +28,19 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Path;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
+import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.InstanceId;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
@@ -57,17 +54,12 @@
 class Bubble implements BubbleViewProvider {
     private static final String TAG = "Bubble";
 
-    /**
-     * NotificationEntry associated with the bubble. A null value implies this bubble is loaded
-     * from disk.
-     */
-    @Nullable
-    private NotificationEntry mEntry;
     private final String mKey;
 
     private long mLastUpdated;
     private long mLastAccessed;
 
+    @Nullable
     private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
 
     /** Whether the bubble should show a dot for the notification indicating updated content. */
@@ -75,8 +67,6 @@
 
     /** Whether flyout text should be suppressed, regardless of any other flags or state. */
     private boolean mSuppressFlyout;
-    /** Whether this bubble should auto expand regardless of the normal flag, used for overflow. */
-    private boolean mShouldAutoExpand;
 
     // Items that are typically loaded later
     private String mAppName;
@@ -92,6 +82,7 @@
      * Presentational info about the flyout.
      */
     public static class FlyoutMessage {
+        @Nullable public Icon senderIcon;
         @Nullable public Drawable senderAvatar;
         @Nullable public CharSequence senderName;
         @Nullable public CharSequence message;
@@ -109,16 +100,39 @@
     private UserHandle mUser;
     @NonNull
     private String mPackageName;
+    @Nullable
+    private String mTitle;
+    @Nullable
+    private Icon mIcon;
+    private boolean mIsBubble;
+    private boolean mIsVisuallyInterruptive;
+    private boolean mIsClearable;
+    private boolean mShouldSuppressNotificationDot;
+    private boolean mShouldSuppressNotificationList;
+    private boolean mShouldSuppressPeek;
     private int mDesiredHeight;
     @DimenRes
     private int mDesiredHeightResId;
 
+    /** for logging **/
+    @Nullable
+    private InstanceId mInstanceId;
+    @Nullable
+    private String mChannelId;
+    private int mNotificationId;
+    private int mAppUid = -1;
+
+    @Nullable
+    private PendingIntent mIntent;
+    @Nullable
+    private PendingIntent mDeleteIntent;
+
     /**
      * Create a bubble with limited information based on given {@link ShortcutInfo}.
      * Note: Currently this is only being used when the bubble is persisted to disk.
      */
     Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
-            final int desiredHeight, final int desiredHeightResId) {
+            final int desiredHeight, final int desiredHeightResId, @Nullable final String title) {
         Objects.requireNonNull(key);
         Objects.requireNonNull(shortcutInfo);
         mShortcutInfo = shortcutInfo;
@@ -126,8 +140,10 @@
         mFlags = 0;
         mUser = shortcutInfo.getUserHandle();
         mPackageName = shortcutInfo.getPackage();
+        mIcon = shortcutInfo.getIcon();
         mDesiredHeight = desiredHeight;
         mDesiredHeightResId = desiredHeightResId;
+        mTitle = title;
     }
 
     /** Used in tests when no UI is required. */
@@ -145,12 +161,6 @@
         return mKey;
     }
 
-    @Nullable
-    public NotificationEntry getEntry() {
-        return mEntry;
-    }
-
-    @NonNull
     public UserHandle getUser() {
         return mUser;
     }
@@ -203,14 +213,7 @@
 
     @Nullable
     public String getTitle() {
-        final CharSequence titleCharSeq;
-        if (mEntry == null) {
-            titleCharSeq = null;
-        } else {
-            titleCharSeq = mEntry.getSbn().getNotification().extras.getCharSequence(
-                    Notification.EXTRA_TITLE);
-        }
-        return titleCharSeq != null ? titleCharSeq.toString() : null;
+        return mTitle;
     }
 
     /**
@@ -331,17 +334,45 @@
     void setEntry(@NonNull final NotificationEntry entry) {
         Objects.requireNonNull(entry);
         Objects.requireNonNull(entry.getSbn());
-        mEntry = entry;
         mLastUpdated = entry.getSbn().getPostTime();
-        mFlags = entry.getSbn().getNotification().flags;
+        mIsBubble = entry.getSbn().getNotification().isBubbleNotification();
         mPackageName = entry.getSbn().getPackageName();
         mUser = entry.getSbn().getUser();
+        mTitle = getTitle(entry);
+        mIsClearable = entry.isClearable();
+        mShouldSuppressNotificationDot = entry.shouldSuppressNotificationDot();
+        mShouldSuppressNotificationList = entry.shouldSuppressNotificationList();
+        mShouldSuppressPeek = entry.shouldSuppressPeek();
+        mChannelId = entry.getSbn().getNotification().getChannelId();
+        mNotificationId = entry.getSbn().getId();
+        mAppUid = entry.getSbn().getUid();
+        mInstanceId = entry.getSbn().getInstanceId();
+        mFlyoutMessage = BubbleViewInfoTask.extractFlyoutMessage(entry);
+        mShortcutInfo = (entry.getBubbleMetadata() != null
+                && entry.getBubbleMetadata().getShortcutId() != null
+                && entry.getRanking() != null) ? entry.getRanking().getShortcutInfo() : null;
+        if (entry.getRanking() != null) {
+            mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive();
+        }
         if (entry.getBubbleMetadata() != null) {
+            mFlags = entry.getBubbleMetadata().getFlags();
             mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight();
             mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId();
+            mIcon = entry.getBubbleMetadata().getIcon();
+            mIntent = entry.getBubbleMetadata().getIntent();
+            mDeleteIntent = entry.getBubbleMetadata().getDeleteIntent();
         }
     }
 
+    @Nullable
+    Icon getIcon() {
+        return mIcon;
+    }
+
+    boolean isVisuallyInterruptive() {
+        return mIsVisuallyInterruptive;
+    }
+
     /**
      * @return the last time this bubble was updated or accessed, whichever is most recent.
      */
@@ -364,6 +395,19 @@
         return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
     }
 
+    public InstanceId getInstanceId() {
+        return mInstanceId;
+    }
+
+    @Nullable
+    public String getChannelId() {
+        return mChannelId;
+    }
+
+    public int getNotificationId() {
+        return mNotificationId;
+    }
+
     /**
      * Should be invoked whenever a Bubble is accessed (selected while expanded).
      */
@@ -384,24 +428,19 @@
      * Whether this notification should be shown in the shade.
      */
     boolean showInShade() {
-        if (mEntry == null) return false;
-        return !shouldSuppressNotification() || !mEntry.isClearable();
+        return !shouldSuppressNotification() || !mIsClearable;
     }
 
     /**
      * Sets whether this notification should be suppressed in the shade.
      */
     void setSuppressNotification(boolean suppressNotification) {
-        if (mEntry == null) return;
         boolean prevShowInShade = showInShade();
-        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
-        int flags = data.getFlags();
         if (suppressNotification) {
-            flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+            mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
         } else {
-            flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+            mFlags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
         }
-        data.setFlags(flags);
 
         if (showInShade() != prevShowInShade && mSuppressionListener != null) {
             mSuppressionListener.onBubbleNotificationSuppressionChange(this);
@@ -424,9 +463,8 @@
      */
     @Override
     public boolean showDot() {
-        if (mEntry == null) return false;
         return mShowBubbleUpdateDot
-                && !mEntry.shouldSuppressNotificationDot()
+                && !mShouldSuppressNotificationDot
                 && !shouldSuppressNotification();
     }
 
@@ -434,10 +472,9 @@
      * Whether the flyout for the bubble should be shown.
      */
     boolean showFlyout() {
-        if (mEntry == null) return false;
-        return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
+        return !mSuppressFlyout && !mShouldSuppressPeek
                 && !shouldSuppressNotification()
-                && !mEntry.shouldSuppressNotificationList();
+                && !mShouldSuppressNotificationList;
     }
 
     /**
@@ -480,25 +517,14 @@
         }
     }
 
-    /**
-     * Whether shortcut information should be used to populate the bubble.
-     * <p>
-     * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
-     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
-     */
-    boolean usingShortcutInfo() {
-        return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null
-                || mShortcutInfo != null;
+    @Nullable
+    PendingIntent getBubbleIntent() {
+        return mIntent;
     }
 
     @Nullable
-    PendingIntent getBubbleIntent() {
-        if (mEntry == null) return null;
-        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
-        if (data != null) {
-            return data.getIntent();
-        }
-        return null;
+    PendingIntent getDeleteIntent() {
+        return mDeleteIntent;
     }
 
     Intent getSettingsIntent(final Context context) {
@@ -514,8 +540,12 @@
         return intent;
     }
 
+    public int getAppUid() {
+        return mAppUid;
+    }
+
     private int getUid(final Context context) {
-        if (mEntry != null) return mEntry.getSbn().getUid();
+        if (mAppUid != -1) return mAppUid;
         final PackageManager pm = context.getPackageManager();
         if (pm == null) return -1;
         try {
@@ -548,24 +578,27 @@
     }
 
     private boolean shouldSuppressNotification() {
-        if (mEntry == null) return true;
-        return mEntry.getBubbleMetadata() != null
-                && mEntry.getBubbleMetadata().isNotificationSuppressed();
+        return isEnabled(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
     }
 
-    boolean shouldAutoExpand() {
-        if (mEntry == null) return mShouldAutoExpand;
-        Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
-        return (metadata != null && metadata.getAutoExpandBubble()) ||  mShouldAutoExpand;
+    public boolean shouldAutoExpand() {
+        return isEnabled(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
     }
 
     void setShouldAutoExpand(boolean shouldAutoExpand) {
-        mShouldAutoExpand = shouldAutoExpand;
+        if (shouldAutoExpand) {
+            enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+        } else {
+            disable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+        }
+    }
+
+    public void setIsBubble(final boolean isBubble) {
+        mIsBubble = isBubble;
     }
 
     public boolean isBubble() {
-        if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0;
-        return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0;
+        return mIsBubble;
     }
 
     public void enable(int option) {
@@ -576,6 +609,10 @@
         mFlags &= ~option;
     }
 
+    public boolean isEnabled(int option) {
+        return (mFlags & option) != 0;
+    }
+
     @Override
     public String toString() {
         return "Bubble{" + mKey + '}';
@@ -610,34 +647,24 @@
 
     @Override
     public void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index) {
-        if (this.getEntry() == null
-                || this.getEntry().getSbn() == null) {
-            SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
-                    null /* package name */,
-                    null /* notification channel */,
-                    0 /* notification ID */,
-                    0 /* bubble position */,
-                    bubbleCount,
-                    action,
-                    normalX,
-                    normalY,
-                    false /* unread bubble */,
-                    false /* on-going bubble */,
-                    false /* isAppForeground (unused) */);
-        } else {
-            StatusBarNotification notification = this.getEntry().getSbn();
-            SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
-                    notification.getPackageName(),
-                    notification.getNotification().getChannelId(),
-                    notification.getId(),
-                    index,
-                    bubbleCount,
-                    action,
-                    normalX,
-                    normalY,
-                    this.showInShade(),
-                    false /* isOngoing (unused) */,
-                    false /* isAppForeground (unused) */);
-        }
+        SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
+                mPackageName,
+                mChannelId,
+                mNotificationId,
+                index,
+                bubbleCount,
+                action,
+                normalX,
+                normalY,
+                showInShade(),
+                false /* isOngoing (unused) */,
+                false /* isAppForeground (unused) */);
+    }
+
+    @Nullable
+    private static String getTitle(@NonNull final NotificationEntry e) {
+        final CharSequence titleCharSeq = e.getSbn().getNotification().extras.getCharSequence(
+                Notification.EXTRA_TITLE);
+        return titleCharSeq == null ? null : titleCharSeq.toString();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index c4c5da4..c429209 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -67,6 +67,7 @@
 import android.util.Pair;
 import android.util.SparseSetArray;
 import android.view.Display;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
@@ -394,6 +395,7 @@
                 : statusBarService;
 
         mBubbleScrim = new ScrimView(mContext);
+        mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
 
         mSavedBubbleKeysPerUser = new SparseSetArray<>();
         mCurrentUserId = mNotifUserManager.getCurrentUserId();
@@ -505,8 +507,7 @@
         addNotifCallback(new NotifCallback() {
             @Override
             public void removeNotification(NotificationEntry entry, int reason) {
-                mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
-                        reason);
+                mNotificationEntryManager.performRemoveNotification(entry.getSbn(), reason);
             }
 
             @Override
@@ -637,8 +638,13 @@
                 mStackView.setExpandListener(mExpandListener);
             }
 
-            mStackView.setUnbubbleConversationCallback(notificationEntry ->
-                    onUserChangedBubble(notificationEntry, false /* shouldBubble */));
+            mStackView.setUnbubbleConversationCallback(key -> {
+                final NotificationEntry entry =
+                        mNotificationEntryManager.getPendingOrActiveNotif(key);
+                if (entry != null) {
+                    onUserChangedBubble(entry, false /* shouldBubble */);
+                }
+            });
         }
 
         addToWindowManagerMaybe();
@@ -1024,10 +1030,7 @@
      * @param entry the notification to change bubble state for.
      * @param shouldBubble whether the notification should show as a bubble or not.
      */
-    public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) {
-        if (entry == null) {
-            return;
-        }
+    public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) {
         NotificationChannel channel = entry.getChannel();
         final String appPkg = entry.getSbn().getPackageName();
         final int appUid = entry.getSbn().getUid();
@@ -1103,7 +1106,8 @@
             mBubbleData.removeSuppressedSummary(groupKey);
 
             // Remove any associated bubble children with the summary
-            final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
+            final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(
+                    groupKey, mNotificationEntryManager);
             for (int i = 0; i < bubbleChildren.size(); i++) {
                 removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED);
             }
@@ -1161,21 +1165,18 @@
 
     private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) {
         Objects.requireNonNull(b);
-        if (isBubble) {
-            b.enable(FLAG_BUBBLE);
-        } else {
-            b.disable(FLAG_BUBBLE);
-        }
-        if (b.getEntry() != null) {
+        b.setIsBubble(isBubble);
+        final NotificationEntry entry = mNotificationEntryManager
+                .getPendingOrActiveNotif(b.getKey());
+        if (entry != null) {
             // Updating the entry to be a bubble will trigger our normal update flow
-            setIsBubble(b.getEntry(), isBubble, b.shouldAutoExpand());
+            setIsBubble(entry, isBubble, b.shouldAutoExpand());
         } else if (isBubble) {
-            // If we have no entry to update, it's a persisted bubble so
-            // we need to add it to the stack ourselves
+            // If bubble doesn't exist, it's a persisted bubble so we need to add it to the
+            // stack ourselves
             Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */);
             inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */,
                     !bubble.shouldAutoExpand() /* showInShade */);
-
         }
     }
 
@@ -1214,6 +1215,8 @@
                 if (reason == DISMISS_NOTIF_CANCEL) {
                     bubblesToBeRemovedFromRepository.add(bubble);
                 }
+                final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+                        bubble.getKey());
                 if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
                     if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
                         && (!bubble.showInShade()
@@ -1222,26 +1225,27 @@
                         // The bubble is now gone & the notification is hidden from the shade, so
                         // time to actually remove it
                         for (NotifCallback cb : mCallbacks) {
-                            if (bubble.getEntry() != null) {
-                                cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
+                            if (entry != null) {
+                                cb.removeNotification(entry, REASON_CANCEL);
                             }
                         }
                     } else {
                         if (bubble.isBubble()) {
                             setIsBubble(bubble, false /* isBubble */);
                         }
-                        if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) {
-                            bubble.getEntry().getRow().updateBubbleButton();
+                        if (entry != null && entry.getRow() != null) {
+                            entry.getRow().updateBubbleButton();
                         }
                     }
 
                 }
-                if (bubble.getEntry() != null) {
-                    final String groupKey = bubble.getEntry().getSbn().getGroupKey();
-                    if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
+                if (entry != null) {
+                    final String groupKey = entry.getSbn().getGroupKey();
+                    if (mBubbleData.getBubblesInGroup(
+                            groupKey, mNotificationEntryManager).isEmpty()) {
                         // Time to potentially remove the summary
                         for (NotifCallback cb : mCallbacks) {
-                            cb.maybeCancelSummary(bubble.getEntry());
+                            cb.maybeCancelSummary(entry);
                         }
                     }
                 }
@@ -1266,9 +1270,12 @@
 
             if (update.selectionChanged && mStackView != null) {
                 mStackView.setSelectedBubble(update.selectedBubble);
-                if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) {
-                    mNotificationGroupManager.updateSuppression(
-                            update.selectedBubble.getEntry());
+                if (update.selectedBubble != null) {
+                    final NotificationEntry entry = mNotificationEntryManager
+                            .getPendingOrActiveNotif(update.selectedBubble.getKey());
+                    if (entry != null) {
+                        mNotificationGroupManager.updateSuppression(entry);
+                    }
                 }
             }
 
@@ -1341,7 +1348,8 @@
         }
 
         String groupKey = entry.getSbn().getGroupKey();
-        ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
+        ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(
+                groupKey, mNotificationEntryManager);
         boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
                 && mBubbleData.getSummaryKey(groupKey).equals(entry.getKey()));
         boolean isSummary = entry.getSbn().getNotification().isGroupSummary();
@@ -1361,9 +1369,15 @@
                     // As far as group manager is concerned, once a child is no longer shown
                     // in the shade, it is essentially removed.
                     Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey());
-                    mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry());
-                    bubbleChild.setSuppressNotification(true);
-                    bubbleChild.setShowDot(false /* show */);
+                    if (bubbleChild != null) {
+                        final NotificationEntry entry = mNotificationEntryManager
+                                .getPendingOrActiveNotif(bubbleChild.getKey());
+                        if (entry != null) {
+                            mNotificationGroupManager.onEntryRemoved(entry);
+                        }
+                        bubbleChild.setSuppressNotification(true);
+                        bubbleChild.setShowDot(false /* show */);
+                    }
                 } else {
                     // non-bubbled children can be removed
                     for (NotifCallback cb : mCallbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 20a9a8c..c870612 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -22,7 +22,6 @@
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
 import android.annotation.NonNull;
-import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.util.Log;
@@ -34,6 +33,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.bubbles.BubbleController.DismissReason;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import java.io.FileDescriptor;
@@ -256,8 +256,7 @@
         }
         mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
         Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
-        suppressFlyout |= bubble.getEntry() == null
-                || !bubble.getEntry().getRanking().visuallyInterruptive();
+        suppressFlyout |= !bubble.isVisuallyInterruptive();
 
         if (prevBubble == null) {
             // Create a new bubble
@@ -335,13 +334,15 @@
      * Retrieves any bubbles that are part of the notification group represented by the provided
      * group key.
      */
-    ArrayList<Bubble> getBubblesInGroup(@Nullable String groupKey) {
+    ArrayList<Bubble> getBubblesInGroup(@Nullable String groupKey, @NonNull
+            NotificationEntryManager nem) {
         ArrayList<Bubble> bubbleChildren = new ArrayList<>();
         if (groupKey == null) {
             return bubbleChildren;
         }
         for (Bubble b : mBubbles) {
-            if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
+            final NotificationEntry entry = nem.getPendingOrActiveNotif(b.getKey());
+            if (entry != null && groupKey.equals(entry.getSbn().getGroupKey())) {
                 bubbleChildren.add(b);
             }
         }
@@ -439,9 +440,7 @@
             Bubble newSelected = mBubbles.get(newIndex);
             setSelectedBubbleInternal(newSelected);
         }
-        if (bubbleToRemove.getEntry() != null) {
-            maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
-        }
+        maybeSendDeleteIntent(reason, bubbleToRemove);
     }
 
     void overflowBubble(@DismissReason int reason, Bubble bubble) {
@@ -611,21 +610,14 @@
         return true;
     }
 
-    private void maybeSendDeleteIntent(@DismissReason int reason,
-            @NonNull final NotificationEntry entry) {
-        if (reason == BubbleController.DISMISS_USER_GESTURE) {
-            Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
-            PendingIntent deleteIntent = bubbleMetadata != null
-                    ? bubbleMetadata.getDeleteIntent()
-                    : null;
-            if (deleteIntent != null) {
-                try {
-                    deleteIntent.send();
-                } catch (PendingIntent.CanceledException e) {
-                    Log.w(TAG, "Failed to send delete intent for bubble with key: "
-                            + entry.getKey());
-                }
-            }
+    private void maybeSendDeleteIntent(@DismissReason int reason, @NonNull final Bubble bubble) {
+        if (reason != BubbleController.DISMISS_USER_GESTURE) return;
+        PendingIntent deleteIntent = bubble.getDeleteIntent();
+        if (deleteIntent == null) return;
+        try {
+            deleteIntent.send();
+        } catch (PendingIntent.CanceledException e) {
+            Log.w(TAG, "Failed to send delete intent for bubble with key: " + bubble.getKey());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index d20f405..0c25d14 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -74,11 +74,15 @@
 
     private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
         return bubbles.mapNotNull { b ->
-            var shortcutId = b.shortcutInfo?.id
-            if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
-            if (shortcutId == null) return@mapNotNull null
-            BubbleEntity(userId, b.packageName, shortcutId, b.key, b.rawDesiredHeight,
-                    b.rawDesiredHeightResId)
+            BubbleEntity(
+                    userId,
+                    b.packageName,
+                    b.shortcutInfo?.id ?: return@mapNotNull null,
+                    b.key,
+                    b.rawDesiredHeight,
+                    b.rawDesiredHeightResId,
+                    b.title
+            )
         }
     }
 
@@ -159,8 +163,13 @@
         val bubbles = entities.mapNotNull { entity ->
             shortcutMap[ShortcutKey(entity.userId, entity.packageName)]
                     ?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id }
-                    ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo, entity.desiredHeight,
-                            entity.desiredHeightResId) }
+                    ?.let { shortcutInfo -> Bubble(
+                            entity.key,
+                            shortcutInfo,
+                            entity.desiredHeight,
+                            entity.desiredHeightResId,
+                            entity.title
+                    ) }
         }
         uiScope.launch { cb(bubbles) }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 4acfbce..959130b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -35,6 +35,7 @@
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
 import android.annotation.SuppressLint;
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.ActivityView;
@@ -126,6 +127,7 @@
 
     private BubbleController mBubbleController = Dependency.get(BubbleController.class);
     private WindowManager mWindowManager;
+    private ActivityManager mActivityManager;
 
     private BubbleStackView mStackView;
     private View mVirtualImeView;
@@ -169,7 +171,7 @@
                             return;
                         }
                         try {
-                            if (!mIsOverflow && mBubble.usingShortcutInfo()) {
+                            if (!mIsOverflow && mBubble.getShortcutInfo() != null) {
                                 options.setApplyActivityFlagsForBubbles(true);
                                 mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
                                         options, null /* sourceBounds */);
@@ -191,6 +193,10 @@
                         }
                     });
                     mActivityViewStatus = ActivityViewStatus.ACTIVITY_STARTED;
+                    break;
+                case ACTIVITY_STARTED:
+                    post(() -> mActivityManager.moveTaskToFront(mTaskId, 0));
+                    break;
             }
         }
 
@@ -252,6 +258,7 @@
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         updateDimensions();
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
     }
 
     void updateDimensions() {
@@ -661,7 +668,7 @@
                 desiredHeight = Math.max(mBubble.getDesiredHeight(mContext), mMinHeight);
             }
             float height = Math.min(desiredHeight, getMaxExpandedHeight());
-            height = Math.max(height, mIsOverflow? mOverflowHeight : mMinHeight);
+            height = Math.max(height, mMinHeight);
             ViewGroup.LayoutParams lp = mActivityView.getLayoutParams();
             mNeedsNewHeight = lp.height != height;
             if (!mKeyboardVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 8c76cda..1fa3aaa 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -31,6 +31,7 @@
 import android.graphics.Path;
 import android.graphics.PointF;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
@@ -223,9 +224,10 @@
             float[] dotCenter,
             boolean hideDot) {
 
-        if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) {
+        final Drawable senderAvatar = flyoutMessage.senderAvatar;
+        if (senderAvatar != null && flyoutMessage.isGroupChat) {
             mSenderAvatar.setVisibility(VISIBLE);
-            mSenderAvatar.setImageDrawable(flyoutMessage.senderAvatar);
+            mSenderAvatar.setImageDrawable(senderAvatar);
         } else {
             mSenderAvatar.setVisibility(GONE);
             mSenderAvatar.setTranslationX(0);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index 74231c6..a799f2d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -15,7 +15,8 @@
  */
 package com.android.systemui.bubbles;
 
-import android.app.Notification;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
@@ -50,15 +51,14 @@
     /**
      * Returns the drawable that the developer has provided to display in the bubble.
      */
-    Drawable getBubbleDrawable(Context context, ShortcutInfo shortcutInfo,
-            Notification.BubbleMetadata metadata) {
+    Drawable getBubbleDrawable(@NonNull final Context context,
+            @Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic) {
         if (shortcutInfo != null) {
             LauncherApps launcherApps =
                     (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
             int density = context.getResources().getConfiguration().densityDpi;
             return launcherApps.getShortcutIconDrawable(shortcutInfo, density);
         } else {
-            Icon ic = metadata.getIcon();
             if (ic != null) {
                 if (ic.getType() == Icon.TYPE_URI
                         || ic.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
index c5faae0..c1dd8c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.bubbles;
 
-import android.service.notification.StatusBarNotification;
-
 import com.android.internal.logging.UiEventLoggerImpl;
 
 /**
@@ -32,12 +30,11 @@
      * @param e UI event
      */
     public void log(Bubble b, UiEventEnum e) {
-        if (b.getEntry() == null) {
+        if (b.getInstanceId() == null) {
             // Added from persistence -- TODO log this with specific event?
             return;
         }
-        StatusBarNotification sbn = b.getEntry().getSbn();
-        logWithInstanceId(e, sbn.getUid(), sbn.getPackageName(), sbn.getInstanceId());
+        logWithInstanceId(e, b.getAppUid(), b.getPackageName(), b.getInstanceId());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index b644079..b943707 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -27,7 +27,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -291,9 +290,7 @@
                 });
 
         // If the bubble was persisted, the entry is null but it should have shortcut info
-        ShortcutInfo info = b.getEntry() == null
-                ? b.getShortcutInfo()
-                : b.getEntry().getRanking().getShortcutInfo();
+        ShortcutInfo info = b.getShortcutInfo();
         if (info == null) {
             Log.d(TAG, "ShortcutInfo required to bubble but none found for " + b);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 23bd174..297d92e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -92,7 +92,6 @@
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.util.DismissCircleView;
 import com.android.systemui.util.FloatingContentCoordinator;
@@ -145,6 +144,12 @@
     @VisibleForTesting
     static final int FLYOUT_HIDE_AFTER = 5000;
 
+    /**
+     * How long to wait to animate the stack temporarily invisible after a drag/flyout hide
+     * animation ends, if we are in fact temporarily invisible.
+     */
+    private static final int ANIMATE_TEMPORARILY_INVISIBLE_DELAY = 1000;
+
     private static final PhysicsAnimator.SpringConfig FLYOUT_IME_ANIMATION_SPRING_CONFIG =
             new PhysicsAnimator.SpringConfig(
                     StackAnimationController.IME_ANIMATION_STIFFNESS,
@@ -281,6 +286,9 @@
     /** Whether or not the stack is temporarily invisible off the side of the screen. */
     private boolean mTemporarilyInvisible = false;
 
+    /** Whether we're in the middle of dragging the stack around by touch. */
+    private boolean mIsDraggingStack = false;
+
     /** Description of current animation controller state. */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Stack view state:");
@@ -294,7 +302,7 @@
     private BubbleController.BubbleExpandListener mExpandListener;
 
     /** Callback to run when we want to unbubble the given notification's conversation. */
-    private Consumer<NotificationEntry> mUnbubbleConversationCallback;
+    private Consumer<String> mUnbubbleConversationCallback;
 
     private SysUiState mSysUiState;
 
@@ -478,6 +486,8 @@
     private OnClickListener mBubbleClickListener = new OnClickListener() {
         @Override
         public void onClick(View view) {
+            mIsDraggingStack = false; // If the touch ended in a click, we're no longer dragging.
+
             // Bubble clicks either trigger expansion/collapse or a bubble switch, both of which we
             // shouldn't interrupt. These are quick transitions, so it's not worth trying to adjust
             // the animations inflight.
@@ -563,6 +573,12 @@
                 // Also, save the magnetized stack so we can dispatch touch events to it.
                 mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget);
                 mMagnetizedObject.setMagnetListener(mStackMagnetListener);
+
+                mIsDraggingStack = true;
+
+                // Cancel animations to make the stack temporarily invisible, since we're now
+                // dragging it.
+                updateTemporarilyInvisibleAnimation(false /* hideImmediately */);
             }
 
             passEventToMagnetizedObject(ev);
@@ -624,6 +640,11 @@
 
                 hideDismissTarget();
             }
+
+            mIsDraggingStack = false;
+
+            // Hide the stack after a delay, if needed.
+            updateTemporarilyInvisibleAnimation(false /* hideImmediately */);
         }
     };
 
@@ -868,14 +889,7 @@
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                     mExpandedAnimationController.updateResources(mOrientation, mDisplaySize);
                     mStackAnimationController.updateResources(mOrientation);
-
-                    // Reposition & adjust the height for new orientation
-                    if (mIsExpanded) {
-                        mExpandedViewContainer.setTranslationY(getExpandedViewY());
-                        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-                            mExpandedBubble.getExpandedView().updateView(getLocationOnScreen());
-                        }
-                    }
+                    mBubbleOverflow.updateDimensions();
 
                     // Need to update the padding around the view
                     WindowInsets insets = getRootWindowInsets();
@@ -899,9 +913,15 @@
 
                     if (mIsExpanded) {
                         // Re-draw bubble row and pointer for new orientation.
+                        beforeExpandedViewAnimation();
+                        updateOverflowVisibility();
+                        updatePointerPosition();
                         mExpandedAnimationController.expandFromStack(() -> {
-                            updatePointerPosition();
+                            afterExpandedViewAnimation();
                         } /* after */);
+                        mExpandedViewContainer.setTranslationX(0);
+                        mExpandedViewContainer.setTranslationY(getExpandedViewY());
+                        mExpandedViewContainer.setAlpha(1f);
                     }
                     if (mVerticalPosPercentBeforeRotation >= 0) {
                         mStackAnimationController.moveStackToSimilarPositionAfterRotation(
@@ -967,14 +987,35 @@
      */
     public void setTemporarilyInvisible(boolean invisible) {
         mTemporarilyInvisible = invisible;
-        animateTemporarilyInvisible();
+
+        // If we are animating out, hide immediately if possible so we animate out with the status
+        // bar.
+        updateTemporarilyInvisibleAnimation(invisible /* hideImmediately */);
     }
 
     /**
-     * Animates onto or off the screen depending on whether we're temporarily invisible, and whether
-     * a flyout is visible.
+     * Animates the stack to be temporarily invisible, if needed.
+     *
+     * If we're currently dragging the stack, or a flyout is visible, the stack will remain visible.
+     * regardless of the value of {@link #mTemporarilyInvisible}. This method is called on ACTION_UP
+     * as well as whenever a flyout hides, so we will animate invisible at that point if needed.
      */
-    private void animateTemporarilyInvisible() {
+    private void updateTemporarilyInvisibleAnimation(boolean hideImmediately) {
+        removeCallbacks(mAnimateTemporarilyInvisibleImmediate);
+
+        if (mIsDraggingStack) {
+            // If we're dragging the stack, don't animate it invisible.
+            return;
+        }
+
+        final boolean shouldHide =
+                mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE;
+
+        postDelayed(mAnimateTemporarilyInvisibleImmediate,
+                shouldHide && !hideImmediately ? ANIMATE_TEMPORARILY_INVISIBLE_DELAY : 0);
+    }
+
+    private final Runnable mAnimateTemporarilyInvisibleImmediate = () -> {
         if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
             if (mStackAnimationController.isStackOnLeftSide()) {
                 animate().translationX(-mBubbleSize).start();
@@ -984,7 +1025,7 @@
         } else {
             animate().translationX(0).start();
         }
-    }
+    };
 
     private void setUpManageMenu() {
         if (mManageMenu != null) {
@@ -1014,10 +1055,7 @@
         mManageMenu.findViewById(R.id.bubble_manage_menu_dont_bubble_container).setOnClickListener(
                 view -> {
                     showManageMenu(false /* show */);
-                    final Bubble bubble = mBubbleData.getSelectedBubble();
-                    if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
-                        mUnbubbleConversationCallback.accept(bubble.getEntry());
-                    }
+                    mUnbubbleConversationCallback.accept(mBubbleData.getSelectedBubble().getKey());
                 });
 
         mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container).setOnClickListener(
@@ -1369,7 +1407,7 @@
 
     /** Sets the function to call to un-bubble the given conversation. */
     public void setUnbubbleConversationCallback(
-            Consumer<NotificationEntry> unbubbleConversationCallback) {
+            Consumer<String> unbubbleConversationCallback) {
         mUnbubbleConversationCallback = unbubbleConversationCallback;
     }
 
@@ -2303,7 +2341,9 @@
                     BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
 
             mFlyout.setVisibility(INVISIBLE);
-            animateTemporarilyInvisible();
+
+            // Hide the stack after a delay, if needed.
+            updateTemporarilyInvisibleAnimation(false /* hideImmediately */);
         };
         mFlyout.setVisibility(INVISIBLE);
 
@@ -2321,7 +2361,7 @@
             final Runnable expandFlyoutAfterDelay = () -> {
                 mAnimateInFlyout = () -> {
                     mFlyout.setVisibility(VISIBLE);
-                    animateTemporarilyInvisible();
+                    updateTemporarilyInvisibleAnimation(false /* hideImmediately */);
                     mFlyoutDragDeltaX =
                             mStackAnimationController.isStackOnLeftSide()
                                     ? -mFlyout.getWidth()
@@ -2470,6 +2510,10 @@
                     .spring(DynamicAnimation.SCALE_Y, 1f)
                     .spring(DynamicAnimation.TRANSLATION_X, targetX)
                     .spring(DynamicAnimation.TRANSLATION_Y, targetY)
+                    .withEndActions(() -> {
+                        View child = mManageMenu.getChildAt(0);
+                        child.requestAccessibilityFocus();
+                    })
                     .start();
 
             mManageMenu.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 525d5b5..3e4ff52 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -37,8 +37,6 @@
 import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
 import android.os.Parcelable;
-import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.PathParser;
@@ -53,6 +51,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Simple task to inflate views & load necessary info to display a bubble.
@@ -129,35 +128,10 @@
         @Nullable
         static BubbleViewInfo populate(Context c, BubbleStackView stackView,
                 BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) {
-            final NotificationEntry entry = b.getEntry();
-            if (entry == null) {
-                // populate from ShortcutInfo when NotificationEntry is not available
-                final ShortcutInfo s = b.getShortcutInfo();
-                return populate(c, stackView, iconFactory, skipInflation || b.isInflated(),
-                        s.getPackage(), s.getUserHandle(), s, null);
-            }
-            final StatusBarNotification sbn = entry.getSbn();
-            final String bubbleShortcutId =  entry.getBubbleMetadata().getShortcutId();
-            final ShortcutInfo si = bubbleShortcutId == null
-                    ? null : entry.getRanking().getShortcutInfo();
-            return populate(
-                    c, stackView, iconFactory, skipInflation || b.isInflated(),
-                    sbn.getPackageName(), sbn.getUser(), si, entry);
-        }
-
-        private static BubbleViewInfo populate(
-                @NonNull final Context c,
-                @NonNull final BubbleStackView stackView,
-                @NonNull final BubbleIconFactory iconFactory,
-                final boolean isInflated,
-                @NonNull final String packageName,
-                @NonNull final UserHandle user,
-                @Nullable final ShortcutInfo shortcutInfo,
-                @Nullable final NotificationEntry entry) {
             BubbleViewInfo info = new BubbleViewInfo();
 
             // View inflation: only should do this once per bubble
-            if (!isInflated) {
+            if (!skipInflation && !b.isInflated()) {
                 LayoutInflater inflater = LayoutInflater.from(c);
                 info.imageView = (BadgedImageView) inflater.inflate(
                         R.layout.bubble_view, stackView, false /* attachToRoot */);
@@ -167,8 +141,8 @@
                 info.expandedView.setStackView(stackView);
             }
 
-            if (shortcutInfo != null) {
-                info.shortcutInfo = shortcutInfo;
+            if (b.getShortcutInfo() != null) {
+                info.shortcutInfo = b.getShortcutInfo();
             }
 
             // App name & app icon
@@ -178,7 +152,7 @@
             Drawable appIcon;
             try {
                 appInfo = pm.getApplicationInfo(
-                        packageName,
+                        b.getPackageName(),
                         PackageManager.MATCH_UNINSTALLED_PACKAGES
                                 | PackageManager.MATCH_DISABLED_COMPONENTS
                                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -186,17 +160,17 @@
                 if (appInfo != null) {
                     info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
                 }
-                appIcon = pm.getApplicationIcon(packageName);
-                badgedIcon = pm.getUserBadgedIcon(appIcon, user);
+                appIcon = pm.getApplicationIcon(b.getPackageName());
+                badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
             } catch (PackageManager.NameNotFoundException exception) {
                 // If we can't find package... don't think we should show the bubble.
-                Log.w(TAG, "Unable to find package: " + packageName);
+                Log.w(TAG, "Unable to find package: " + b.getPackageName());
                 return null;
             }
 
             // Badged bubble image
             Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
-                    entry == null ? null : entry.getBubbleMetadata());
+                    b.getIcon());
             if (bubbleDrawable == null) {
                 // Default to app icon
                 bubbleDrawable = appIcon;
@@ -222,8 +196,10 @@
                     Color.WHITE, WHITE_SCRIM_ALPHA);
 
             // Flyout
-            if (entry != null) {
-                info.flyoutMessage = extractFlyoutMessage(c, entry);
+            info.flyoutMessage = b.getFlyoutMessage();
+            if (info.flyoutMessage != null) {
+                info.flyoutMessage.senderAvatar =
+                        loadSenderAvatar(c, info.flyoutMessage.senderIcon);
             }
             return info;
         }
@@ -235,8 +211,8 @@
      * notification, based on its type. Returns null if there should not be an update message.
      */
     @NonNull
-    static Bubble.FlyoutMessage extractFlyoutMessage(Context context,
-            NotificationEntry entry) {
+    static Bubble.FlyoutMessage extractFlyoutMessage(NotificationEntry entry) {
+        Objects.requireNonNull(entry);
         final Notification underlyingNotif = entry.getSbn().getNotification();
         final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
 
@@ -264,20 +240,9 @@
                 if (latestMessage != null) {
                     bubbleMessage.message = latestMessage.getText();
                     Person sender = latestMessage.getSenderPerson();
-                    bubbleMessage.senderName = sender != null
-                            ? sender.getName()
-                            : null;
-
+                    bubbleMessage.senderName = sender != null ? sender.getName() : null;
                     bubbleMessage.senderAvatar = null;
-                    if (sender != null && sender.getIcon() != null) {
-                        if (sender.getIcon().getType() == Icon.TYPE_URI
-                                || sender.getIcon().getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
-                            context.grantUriPermission(context.getPackageName(),
-                                    sender.getIcon().getUri(),
-                                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                        }
-                        bubbleMessage.senderAvatar = sender.getIcon().loadDrawable(context);
-                    }
+                    bubbleMessage.senderIcon = sender != null ? sender.getIcon() : null;
                     return bubbleMessage;
                 }
             } else if (Notification.InboxStyle.class.equals(style)) {
@@ -306,4 +271,15 @@
 
         return bubbleMessage;
     }
+
+    @Nullable
+    static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
+        Objects.requireNonNull(context);
+        if (icon == null) return null;
+        if (icon.getType() == Icon.TYPE_URI || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+            context.grantUriPermission(context.getPackageName(),
+                    icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        }
+        return icon.loadDrawable(context);
+    }
 }
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 cb8995a..8e23252 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -203,12 +203,22 @@
     public void updateResources(int orientation, Point displaySize) {
         mScreenOrientation = orientation;
         mDisplaySize = displaySize;
-        if (mLayout != null) {
-            Resources res = mLayout.getContext().getResources();
-            mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
-            mStatusBarHeight = res.getDimensionPixelSize(
-                    com.android.internal.R.dimen.status_bar_height);
+        if (mLayout == null) {
+            return;
         }
+        Resources res = mLayout.getContext().getResources();
+        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
+        mStatusBarHeight = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+        mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
+        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
+        mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
+        mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
+
+        // Includes overflow button.
+        float totalGapWidth = getWidthForDisplayingBubbles() - (mExpandedViewPadding * 2)
+                - (mBubblesMaxRendered + 1) * mBubbleSizePx;
+        mSpaceBetweenBubbles = totalGapWidth / mBubblesMaxRendered;
     }
 
     /**
@@ -464,18 +474,7 @@
 
     @Override
     void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
-        final Resources res = layout.getResources();
-        mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
-        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
-        mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
-        mStatusBarHeight =
-                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
-
-        // Includes overflow button.
-        float totalGapWidth = getWidthForDisplayingBubbles() - (mExpandedViewPadding * 2)
-                - (mBubblesMaxRendered + 1) * mBubbleSizePx;
-        mSpaceBetweenBubbles = totalGapWidth / mBubblesMaxRendered;
+        updateResources(mScreenOrientation, mDisplaySize);
 
         // Ensure that all child views are at 1x scale, and visible, in case they were animating
         // in.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
index 355c4b1..24768cd 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
@@ -24,5 +24,6 @@
     val shortcutId: String,
     val key: String,
     val desiredHeight: Int,
-    @DimenRes val desiredHeightResId: Int
+    @DimenRes val desiredHeightResId: Int,
+    val title: String? = null
 )
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
index a8faf25..66fff338 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
@@ -33,6 +33,7 @@
 private const val ATTR_KEY = "key"
 private const val ATTR_DESIRED_HEIGHT = "h"
 private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid"
+private const val ATTR_TITLE = "t"
 
 /**
  * Writes the bubbles in xml format into given output stream.
@@ -63,6 +64,7 @@
         serializer.attribute(null, ATTR_KEY, bubble.key)
         serializer.attribute(null, ATTR_DESIRED_HEIGHT, bubble.desiredHeight.toString())
         serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString())
+        bubble.title?.let { serializer.attribute(null, ATTR_TITLE, it) }
         serializer.endTag(null, TAG_BUBBLE)
     } catch (e: IOException) {
         throw RuntimeException(e)
@@ -92,7 +94,8 @@
             parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null,
             parser.getAttributeWithName(ATTR_KEY) ?: return null,
             parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null,
-            parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null
+            parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null,
+            parser.getAttributeWithName(ATTR_TITLE)
     )
 }
 
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 0f5aef7..1eb7e21 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -103,6 +103,22 @@
     private lateinit var dismissGlobalActions: Runnable
     private val popupThemedContext = ContextThemeWrapper(context, R.style.Control_ListPopupWindow)
 
+    private val collator = Collator.getInstance(context.resources.configuration.locales[0])
+    private val localeComparator = compareBy<SelectionItem, CharSequence>(collator) {
+        it.getTitle()
+    }
+
+    private val onSeedingComplete = Consumer<Boolean> {
+        accepted ->
+            if (accepted) {
+                selectedStructure = controlsController.get().getFavorites().maxBy {
+                    it.controls.size
+                } ?: EMPTY_STRUCTURE
+                updatePreferences(selectedStructure)
+            }
+            reload(parent)
+    }
+
     override val available: Boolean
         get() = controlsController.get().available
 
@@ -113,22 +129,13 @@
     ): ControlsListingController.ControlsListingCallback {
         return object : ControlsListingController.ControlsListingCallback {
             override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
-                bgExecutor.execute {
-                    val collator = Collator.getInstance(context.resources.configuration.locales[0])
-                    val localeComparator = compareBy<ControlsServiceInfo, CharSequence>(collator) {
-                        it.loadLabel()
-                    }
-
-                    val mList = serviceInfos.toMutableList()
-                    mList.sortWith(localeComparator)
-                    lastItems = mList.map {
-                        SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
-                    }
-                    uiExecutor.execute {
-                        parent.removeAllViews()
-                        if (lastItems.size > 0) {
-                            onResult(lastItems)
-                        }
+                val lastItems = serviceInfos.map {
+                    SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
+                }
+                uiExecutor.execute {
+                    parent.removeAllViews()
+                    if (lastItems.size > 0) {
+                        onResult(lastItems)
                     }
                 }
             }
@@ -144,8 +151,7 @@
         allStructures = controlsController.get().getFavorites()
         selectedStructure = loadPreference(allStructures)
 
-        val cb = Consumer<Boolean> { _ -> reload(parent) }
-        if (controlsController.get().addSeedingFavoritesCallback(cb)) {
+        if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) {
             listingCallback = createCallback(::showSeedingView)
         } else if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) {
             // only show initial view if there are really no favorites across any structure
@@ -309,9 +315,12 @@
         }
 
         val itemsByComponent = items.associateBy { it.componentName }
-        val itemsWithStructure = allStructures.mapNotNull {
+        val itemsWithStructure = mutableListOf<SelectionItem>()
+        allStructures.mapNotNullTo(itemsWithStructure) {
             itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
         }
+        itemsWithStructure.sortWith(localeComparator)
+
         val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
 
         var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
@@ -441,6 +450,7 @@
     }
 
     private fun updatePreferences(si: StructureInfo) {
+        if (si == EMPTY_STRUCTURE) return
         sharedPreferences.edit()
             .putString(PREF_COMPONENT, si.componentName.flattenToString())
             .putString(PREF_STRUCTURE, si.structure.toString())
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 88bdaec..5300795 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -261,7 +261,7 @@
                 }
                 it.active = !timedOut
                 onMediaDataLoaded(token, token, it)
-            } else {
+            } else if (timedOut) {
                 notificationEntryManager.removeNotification(it.notificationKey, null /* ranking */,
                         UNDEFINED_DISMISS_REASON)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index e0155a1..cf8a636 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -82,6 +82,7 @@
 
         init {
             mediaController?.registerCallback(this)
+            onPlaybackStateChanged(mediaController?.playbackState)
         }
 
         fun destroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
index 9b9a6b4..bccc3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
@@ -13,6 +13,7 @@
 import com.android.systemui.R
 import com.android.systemui.qs.PageIndicator
 import com.android.systemui.statusbar.notification.VisualStabilityManager
+import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.animation.UniqueObjectHostView
 import com.android.systemui.util.animation.requiresRemeasuring
 import javax.inject.Inject
@@ -31,7 +32,8 @@
     private val mediaControlPanelFactory: Provider<MediaControlPanel>,
     private val visualStabilityManager: VisualStabilityManager,
     private val mediaHostStatesManager: MediaHostStatesManager,
-    mediaManager: MediaDataCombineLatest
+    mediaManager: MediaDataCombineLatest,
+    configurationController: ConfigurationController
 ) {
 
     /**
@@ -74,6 +76,7 @@
     private val mediaCarousel: HorizontalScrollView
     val mediaFrame: ViewGroup
     val mediaPlayers: MutableMap<String, MediaControlPanel> = mutableMapOf()
+    private val mediaData: MutableMap<String, MediaData> = mutableMapOf()
     private val mediaContent: ViewGroup
     private val pageIndicator: PageIndicator
     private val gestureDetector: GestureDetectorCompat
@@ -120,6 +123,11 @@
             return this@MediaViewManager.onTouch(view, motionEvent)
         }
     }
+    private val configListener = object : ConfigurationController.ConfigurationListener {
+        override fun onDensityOrFontScaleChanged() {
+            recreatePlayers()
+        }
+    }
 
     init {
         gestureDetector = GestureDetectorCompat(context, gestureListener)
@@ -130,6 +138,7 @@
         mediaCarousel.setOnTouchListener(touchListener)
         mediaCarousel.setOverScrollMode(View.OVER_SCROLL_NEVER)
         mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
+        configurationController.addCallback(configListener)
         visualStabilityCallback = VisualStabilityManager.Callback {
             if (needsReordering) {
                 needsReordering = false
@@ -142,29 +151,14 @@
                 true /* persistent */)
         mediaManager.addListener(object : MediaDataManager.Listener {
             override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
-                updateView(key, oldKey, data)
-                updatePlayerVisibilities()
-                mediaCarousel.requiresRemeasuring = true
+                oldKey?.let { mediaData.remove(it) }
+                mediaData.put(key, data)
+                addOrUpdatePlayer(key, oldKey, data)
             }
 
             override fun onMediaDataRemoved(key: String) {
-                val removed = mediaPlayers.remove(key)
-                removed?.apply {
-                    val beforeActive = mediaContent.indexOfChild(removed.view?.player) <=
-                            activeMediaIndex
-                    mediaContent.removeView(removed.view?.player)
-                    removed.onDestroy()
-                    updateMediaPaddings()
-                    if (beforeActive) {
-                        // also update the index here since the scroll below might not always lead
-                        // to a scrolling changed
-                        activeMediaIndex = Math.max(0, activeMediaIndex - 1)
-                        mediaCarousel.scrollX = Math.max(mediaCarousel.scrollX -
-                                playerWidthPlusPadding, 0)
-                    }
-                    updatePlayerVisibilities()
-                    updatePageIndicator()
-                }
+                mediaData.remove(key)
+                removePlayer(key)
             }
         })
         mediaHostStatesManager.addCallback(object : MediaHostStatesManager.Callback {
@@ -253,7 +247,7 @@
         }
     }
 
-    private fun updateView(key: String, oldKey: String?, data: MediaData) {
+    private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) {
         // If the key was changed, update entry
         val oldData = mediaPlayers[oldKey]
         if (oldData != null) {
@@ -288,6 +282,39 @@
         existingPlayer?.bind(data)
         updateMediaPaddings()
         updatePageIndicator()
+        updatePlayerVisibilities()
+        mediaCarousel.requiresRemeasuring = true
+    }
+
+    private fun removePlayer(key: String) {
+        val removed = mediaPlayers.remove(key)
+        removed?.apply {
+            val beforeActive = mediaContent.indexOfChild(removed.view?.player) <=
+                    activeMediaIndex
+            mediaContent.removeView(removed.view?.player)
+            removed.onDestroy()
+            updateMediaPaddings()
+            if (beforeActive) {
+                // also update the index here since the scroll below might not always lead
+                // to a scrolling changed
+                activeMediaIndex = Math.max(0, activeMediaIndex - 1)
+                mediaCarousel.scrollX = Math.max(mediaCarousel.scrollX -
+                        playerWidthPlusPadding, 0)
+            }
+            updatePlayerVisibilities()
+            updatePageIndicator()
+        }
+    }
+
+    private fun recreatePlayers() {
+        // Note that this will scramble the order of players. Actively playing sessions will, at
+        // least, still be put in the front. If we want to maintain order, then more work is
+        // needed.
+        mediaData.forEach {
+            key, data ->
+            removePlayer(key)
+            addOrUpdatePlayer(key = key, oldKey = null, data = data)
+        }
     }
 
     private fun updateMediaPaddings() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index b93e07e..9daa876 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -708,6 +708,12 @@
             Log.w(TAG, "Abort animation, invalid leash");
             return;
         }
+
+        if (startBounds.isEmpty() || destinationBounds.isEmpty()) {
+            Log.w(TAG, "Attempted to user resize PIP to or from empty bounds, aborting.");
+            return;
+        }
+
         final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
         mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
         tx.apply();
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 856c192..06c98d0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Debug;
 import android.util.Log;
@@ -38,6 +39,9 @@
 import java.io.PrintWriter;
 import java.util.function.Consumer;
 
+import kotlin.Unit;
+import kotlin.jvm.functions.Function0;
+
 /**
  * A helper to animate and manipulate the PiP.
  */
@@ -74,9 +78,15 @@
             new SfVsyncFrameCallbackProvider();
 
     /**
-     * Bounds that are animated using the physics animator.
+     * Temporary bounds used when PIP is being dragged or animated. These bounds are applied to PIP
+     * using {@link PipTaskOrganizer#scheduleUserResizePip}, so that we can animate shrinking into
+     * and expanding out of the magnetic dismiss target.
+     *
+     * Once PIP is done being dragged or animated, we set {@link #mBounds} equal to these temporary
+     * bounds, and call {@link PipTaskOrganizer#scheduleFinishResizePip} to 'officially' move PIP to
+     * its new bounds.
      */
-    private final Rect mAnimatedBounds = new Rect();
+    private final Rect mTemporaryBounds = new Rect();
 
     /** The destination bounds to which PIP is animating. */
     private final Rect mAnimatingToBounds = new Rect();
@@ -85,20 +95,20 @@
     private FloatingContentCoordinator mFloatingContentCoordinator;
 
     /** Callback that re-sizes PIP to the animated bounds. */
-    private final Choreographer.FrameCallback mResizePipVsyncCallback =
-            l -> resizePipUnchecked(mAnimatedBounds);
+    private final Choreographer.FrameCallback mResizePipVsyncCallback;
 
     /**
-     * PhysicsAnimator instance for animating {@link #mAnimatedBounds} using physics animations.
+     * PhysicsAnimator instance for animating {@link #mTemporaryBounds} using physics animations.
      */
-    private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
-            mAnimatedBounds);
+    private PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
+            mTemporaryBounds);
+
+    private MagnetizedObject<Rect> mMagnetizedPip;
 
     /**
-     * Update listener that resizes the PIP to {@link #mAnimatedBounds}.
+     * Update listener that resizes the PIP to {@link #mTemporaryBounds}.
      */
-    final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
-            (target, values) -> mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
+    private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener;
 
     /** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
     private PhysicsAnimator.FlingConfig mFlingConfigX;
@@ -124,6 +134,12 @@
     private boolean mSpringingToTouch = false;
 
     /**
+     * Whether PIP was released in the dismiss target, and will be animated out and dismissed
+     * shortly.
+     */
+    private boolean mDismissalPending = false;
+
+    /**
      * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is
      * used to show menu activity when the expand animation is completed.
      */
@@ -155,6 +171,16 @@
         mSnapAlgorithm = snapAlgorithm;
         mFloatingContentCoordinator = floatingContentCoordinator;
         mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
+
+        mResizePipVsyncCallback = l -> {
+            if (!mTemporaryBounds.isEmpty()) {
+                mPipTaskOrganizer.scheduleUserResizePip(
+                        mBounds, mTemporaryBounds, null);
+            }
+        };
+
+        mResizePipUpdateListener = (target, values) ->
+                mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
     }
 
     @NonNull
@@ -186,19 +212,8 @@
         }
     }
 
-    /**
-     * Synchronizes the current bounds with either the pinned stack, or the ongoing animation. This
-     * is done to prepare for a touch gesture.
-     */
-    void synchronizePinnedStackBoundsForTouchGesture() {
-        if (mAnimatingToBounds.isEmpty()) {
-            // If we're not animating anywhere, sync normally.
-            synchronizePinnedStackBounds();
-        } else {
-            // If we're animating, set the current bounds to the animated bounds. That way, the
-            // touch gesture will begin at the most recent animated location of the bounds.
-            mBounds.set(mAnimatedBounds);
-        }
+    boolean isAnimating() {
+        return mTemporaryBoundsPhysicsAnimator.isRunning();
     }
 
     /**
@@ -224,32 +239,54 @@
             // If we are moving PIP directly to the touch event locations, cancel any animations and
             // move PIP to the given bounds.
             cancelAnimations();
-            resizePipUnchecked(toBounds);
-            mBounds.set(toBounds);
+
+            if (!isDragging) {
+                resizePipUnchecked(toBounds);
+                mBounds.set(toBounds);
+            } else {
+                mTemporaryBounds.set(toBounds);
+                mPipTaskOrganizer.scheduleUserResizePip(mBounds, mTemporaryBounds, null);
+            }
         } else {
             // If PIP is 'catching up' after being stuck in the dismiss target, update the animation
             // to spring towards the new touch location.
-            mAnimatedBoundsPhysicsAnimator
+            mTemporaryBoundsPhysicsAnimator
+                    .spring(FloatProperties.RECT_WIDTH, mBounds.width(), mSpringConfig)
+                    .spring(FloatProperties.RECT_HEIGHT, mBounds.height(), mSpringConfig)
                     .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig)
-                    .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig)
-                    .withEndActions(() -> mSpringingToTouch = false);
+                    .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig);
 
             startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */,
                     false /* dismiss */);
         }
     }
 
-    /** Set whether we're springing-to-touch to catch up after being stuck in the dismiss target. */
-    void setSpringingToTouch(boolean springingToTouch) {
-        if (springingToTouch) {
-            mAnimatedBounds.set(mBounds);
-        }
+    /** Animates the PIP into the dismiss target, scaling it down. */
+    void animateIntoDismissTarget(
+            MagnetizedObject.MagneticTarget target,
+            float velX, float velY,
+            boolean flung, Function0<Unit> after) {
+        final PointF targetCenter = target.getCenterOnScreen();
 
-        mSpringingToTouch = springingToTouch;
+        final float desiredWidth = mBounds.width() / 2;
+        final float desiredHeight = mBounds.height() / 2;
+
+        final float destinationX = targetCenter.x - (desiredWidth / 2f);
+        final float destinationY = targetCenter.y - (desiredHeight / 2f);
+
+        mTemporaryBoundsPhysicsAnimator
+                .spring(FloatProperties.RECT_X, destinationX, velX, mSpringConfig)
+                .spring(FloatProperties.RECT_Y, destinationY, velY, mSpringConfig)
+                .spring(FloatProperties.RECT_WIDTH, desiredWidth, mSpringConfig)
+                .spring(FloatProperties.RECT_HEIGHT, desiredHeight, mSpringConfig)
+                .withEndActions(after);
+
+        startBoundsAnimator(destinationX, destinationY, false);
     }
 
-    void prepareForAnimation() {
-        mAnimatedBounds.set(mBounds);
+    /** Set whether we're springing-to-touch to catch up after being stuck in the dismiss target. */
+    void setSpringingToTouch(boolean springingToTouch) {
+        mSpringingToTouch = springingToTouch;
     }
 
     /**
@@ -309,13 +346,22 @@
     }
 
     /**
+     * Returns the PIP bounds if we're not animating, or the current, temporary animating bounds
+     * otherwise.
+     */
+    Rect getPossiblyAnimatingBounds() {
+        return mTemporaryBounds.isEmpty() ? mBounds : mTemporaryBounds;
+    }
+
+    /**
      * Flings the PiP to the closest snap target.
      */
     void flingToSnapTarget(
             float velocityX, float velocityY,
             @Nullable Runnable updateAction, @Nullable Runnable endAction) {
-        mAnimatedBounds.set(mBounds);
-        mAnimatedBoundsPhysicsAnimator
+        mTemporaryBoundsPhysicsAnimator
+                .spring(FloatProperties.RECT_WIDTH, mBounds.width(), mSpringConfig)
+                .spring(FloatProperties.RECT_HEIGHT, mBounds.height(), mSpringConfig)
                 .flingThenSpring(
                         FloatProperties.RECT_X, velocityX, mFlingConfigX, mSpringConfig,
                         true /* flingMustReachMinOrMax */)
@@ -324,13 +370,14 @@
                 .withEndActions(endAction);
 
         if (updateAction != null) {
-            mAnimatedBoundsPhysicsAnimator.addUpdateListener(
+            mTemporaryBoundsPhysicsAnimator.addUpdateListener(
                     (target, values) -> updateAction.run());
         }
 
         final float xEndValue = velocityX < 0 ? mMovementBounds.left : mMovementBounds.right;
         final float estimatedFlingYEndValue =
-                PhysicsAnimator.estimateFlingEndValue(mBounds.top, velocityY, mFlingConfigY);
+                PhysicsAnimator.estimateFlingEndValue(
+                        mTemporaryBounds.top, velocityY, mFlingConfigY);
 
         startBoundsAnimator(xEndValue /* toX */, estimatedFlingYEndValue /* toY */,
                 false /* dismiss */);
@@ -341,8 +388,12 @@
      * configuration
      */
     void animateToBounds(Rect bounds, PhysicsAnimator.SpringConfig springConfig) {
-        mAnimatedBounds.set(mBounds);
-        mAnimatedBoundsPhysicsAnimator
+        if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
+            // Animate from the current bounds if we're not already animating.
+            mTemporaryBounds.set(mBounds);
+        }
+
+        mTemporaryBoundsPhysicsAnimator
                 .spring(FloatProperties.RECT_X, bounds.left, springConfig)
                 .spring(FloatProperties.RECT_Y, bounds.top, springConfig);
         startBoundsAnimator(bounds.left /* toX */, bounds.top /* toY */,
@@ -353,18 +404,19 @@
      * Animates the dismissal of the PiP off the edge of the screen.
      */
     void animateDismiss() {
-        mAnimatedBounds.set(mBounds);
-
         // Animate off the bottom of the screen, then dismiss PIP.
-        mAnimatedBoundsPhysicsAnimator
+        mTemporaryBoundsPhysicsAnimator
                 .spring(FloatProperties.RECT_Y,
-                        mBounds.bottom + mBounds.height(),
+                        mMovementBounds.bottom + mBounds.height() * 2,
                         0,
                         mSpringConfig)
                 .withEndActions(this::dismissPip);
 
-        startBoundsAnimator(mBounds.left /* toX */, mBounds.bottom + mBounds.height() /* toY */,
+        startBoundsAnimator(
+                mBounds.left /* toX */, mBounds.bottom + mBounds.height() /* toY */,
                 true /* dismiss */);
+
+        mDismissalPending = false;
     }
 
     /**
@@ -415,7 +467,7 @@
      * Cancels all existing animations.
      */
     private void cancelAnimations() {
-        mAnimatedBoundsPhysicsAnimator.cancel();
+        mTemporaryBoundsPhysicsAnimator.cancel();
         mAnimatingToBounds.setEmpty();
         mSpringingToTouch = false;
     }
@@ -449,15 +501,36 @@
                 (int) toY + mBounds.height());
         setAnimatingToBounds(mAnimatingToBounds);
 
-        mAnimatedBoundsPhysicsAnimator
-                .withEndActions(() -> {
-                    if (!dismiss) {
-                        mPipTaskOrganizer.scheduleFinishResizePip(mAnimatedBounds);
-                    }
-                    mAnimatingToBounds.setEmpty();
-                })
-                .addUpdateListener(mResizePipUpdateListener)
-                .start();
+        if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
+            mTemporaryBoundsPhysicsAnimator
+                    .addUpdateListener(mResizePipUpdateListener)
+                    .withEndActions(this::onBoundsAnimationEnd);
+        }
+
+        mTemporaryBoundsPhysicsAnimator.start();
+    }
+
+    /**
+     * Notify that PIP was released in the dismiss target and will be animated out and dismissed
+     * shortly.
+     */
+    void notifyDismissalPending() {
+        mDismissalPending = true;
+    }
+
+    private void onBoundsAnimationEnd() {
+        if (!mDismissalPending
+                && !mSpringingToTouch
+                && !mMagnetizedPip.getObjectStuckToTarget()) {
+            mBounds.set(mTemporaryBounds);
+            mPipTaskOrganizer.scheduleFinishResizePip(mBounds);
+
+            mTemporaryBounds.setEmpty();
+        }
+
+        mAnimatingToBounds.setEmpty();
+        mSpringingToTouch = false;
+        mDismissalPending = false;
     }
 
     /**
@@ -503,25 +576,29 @@
      * magnetic dismiss target so it can calculate PIP's size and position.
      */
     MagnetizedObject<Rect> getMagnetizedPip() {
-        return new MagnetizedObject<Rect>(
-                mContext, mAnimatedBounds, FloatProperties.RECT_X, FloatProperties.RECT_Y) {
-            @Override
-            public float getWidth(@NonNull Rect animatedPipBounds) {
-                return animatedPipBounds.width();
-            }
+        if (mMagnetizedPip == null) {
+            mMagnetizedPip = new MagnetizedObject<Rect>(
+                    mContext, mTemporaryBounds, FloatProperties.RECT_X, FloatProperties.RECT_Y) {
+                @Override
+                public float getWidth(@NonNull Rect animatedPipBounds) {
+                    return animatedPipBounds.width();
+                }
 
-            @Override
-            public float getHeight(@NonNull Rect animatedPipBounds) {
-                return animatedPipBounds.height();
-            }
+                @Override
+                public float getHeight(@NonNull Rect animatedPipBounds) {
+                    return animatedPipBounds.height();
+                }
 
-            @Override
-            public void getLocationOnScreen(
-                    @NonNull Rect animatedPipBounds, @NonNull int[] loc) {
-                loc[0] = animatedPipBounds.left;
-                loc[1] = animatedPipBounds.top;
-            }
-        };
+                @Override
+                public void getLocationOnScreen(
+                        @NonNull Rect animatedPipBounds, @NonNull int[] loc) {
+                    loc[0] = animatedPipBounds.left;
+                    loc[1] = animatedPipBounds.top;
+                }
+            };
+        }
+
+        return mMagnetizedPip;
     }
 
     public void dump(PrintWriter pw, String prefix) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 3cc9127..2f9b29d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -70,6 +70,8 @@
 
 import java.io.PrintWriter;
 
+import kotlin.Unit;
+
 /**
  * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
  * the PIP.
@@ -262,12 +264,14 @@
         mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
         updateMagneticTargetSize();
 
-        mMagnetizedPip.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener);
+        mMagnetizedPip.setAnimateStuckToTarget(
+                (target, velX, velY, flung, after) -> {
+                    mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after);
+                    return Unit.INSTANCE;
+                });
         mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
             @Override
             public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                mMotionHelper.prepareForAnimation();
-
                 // Show the dismiss target, in case the initial touch event occurred within the
                 // magnetic field radius.
                 showDismissTargetMaybe();
@@ -286,12 +290,13 @@
 
             @Override
             public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+                mMotionHelper.notifyDismissalPending();
+
                 mHandler.post(() -> {
                     mMotionHelper.animateDismiss();
                     hideDismissTarget();
                 });
 
-
                 MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext,
                         PipUtils.getTopPipActivity(mContext, mActivityManager));
             }
@@ -617,11 +622,16 @@
         }
 
         MotionEvent ev = (MotionEvent) inputEvent;
-
-        if (mPipResizeGestureHandler.isWithinTouchRegion((int) ev.getRawX(), (int) ev.getRawY())) {
+        if (!mTouchState.isDragging()
+                && !mMagnetizedPip.getObjectStuckToTarget()
+                && !mMotionHelper.isAnimating()
+                && mPipResizeGestureHandler.isWithinTouchRegion(
+                        (int) ev.getRawX(), (int) ev.getRawY())) {
             return true;
         }
-        if (mMagnetizedPip.maybeConsumeMotionEvent(ev)) {
+
+        if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting())
+                && mMagnetizedPip.maybeConsumeMotionEvent(ev)) {
             // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
             // to the touch state. Touch state needs a DOWN event in order to later process MOVE
             // events it'll receive if the object is dragged out of the magnetic field.
@@ -643,7 +653,6 @@
 
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN: {
-                mMotionHelper.synchronizePinnedStackBoundsForTouchGesture();
                 mGesture.onDown(mTouchState);
                 break;
             }
@@ -688,11 +697,11 @@
                 break;
             }
             case MotionEvent.ACTION_HOVER_EXIT: {
-                mHideMenuAfterShown = true;
                 // If Touch Exploration is enabled, some a11y services (e.g. Talkback) is probably
                 // on and changing MotionEvents into HoverEvents.
                 // Let's not enable menu show/hide for a11y services.
                 if (!mAccessibilityManager.isTouchExplorationEnabled()) {
+                    mHideMenuAfterShown = true;
                     mMenuController.hideMenu();
                 }
                 if (!shouldDeliverToMenu && mSendingHoverAccessibilityEvents) {
@@ -872,7 +881,7 @@
                 return;
             }
 
-            Rect bounds = mMotionHelper.getBounds();
+            Rect bounds = mMotionHelper.getPossiblyAnimatingBounds();
             mDelta.set(0f, 0f);
             mStartPosition.set(bounds.left, bounds.top);
             mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
@@ -914,7 +923,7 @@
                 mDelta.x += left - lastX;
                 mDelta.y += top - lastY;
 
-                mTmpBounds.set(mMotionHelper.getBounds());
+                mTmpBounds.set(mMotionHelper.getPossiblyAnimatingBounds());
                 mTmpBounds.offsetTo((int) left, (int) top);
                 mMotionHelper.movePip(mTmpBounds, true /* isDragging */);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 43b4723..8c7e071 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,9 +16,15 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricSourceType;
@@ -43,6 +49,7 @@
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -78,15 +85,19 @@
     private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
 
     private final Context mContext;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private final KeyguardStateController mKeyguardStateController;
     private final StatusBarStateController mStatusBarStateController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private ViewGroup mIndicationArea;
     private KeyguardIndicationTextView mTextView;
+    private KeyguardIndicationTextView mDisclosure;
     private final IBatteryStats mBatteryInfo;
     private final SettableWakeLock mWakeLock;
     private final DockManager mDockManager;
+    private final DevicePolicyManager mDevicePolicyManager;
 
+    private BroadcastReceiver mBroadcastReceiver;
     private LockscreenLockIconController mLockIconController;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
@@ -105,6 +116,7 @@
     private int mChargingWattage;
     private int mBatteryLevel;
     private long mChargingTimeRemaining;
+    private float mDisclosureMaxAlpha;
     private String mMessageToShowOnScreenOn;
 
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -128,8 +140,12 @@
             StatusBarStateController statusBarStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             DockManager dockManager,
+            BroadcastDispatcher broadcastDispatcher,
+            DevicePolicyManager devicePolicyManager,
             IBatteryStats iBatteryStats) {
         mContext = context;
+        mBroadcastDispatcher = broadcastDispatcher;
+        mDevicePolicyManager = devicePolicyManager;
         mKeyguardStateController = keyguardStateController;
         mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -151,7 +167,22 @@
         mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
         mInitialTextColorState = mTextView != null ?
                 mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
+        mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
+        mDisclosureMaxAlpha = mDisclosure.getAlpha();
         updateIndication(false /* animate */);
+        updateDisclosure();
+
+        if (mBroadcastReceiver == null) {
+            // Update the disclosure proactively to avoid IPC on the critical path.
+            mBroadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    updateDisclosure();
+                }
+            };
+            mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, new IntentFilter(
+                    DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED));
+        }
     }
 
     public void setLockIconController(LockscreenLockIconController lockIconController) {
@@ -190,6 +221,23 @@
         return mUpdateMonitorCallback;
     }
 
+    private void updateDisclosure() {
+        // NOTE: Because this uses IPC, avoid calling updateDisclosure() on a critical path.
+        if (whitelistIpcs(mDevicePolicyManager::isDeviceManaged)) {
+            final CharSequence organizationName =
+                    mDevicePolicyManager.getDeviceOwnerOrganizationName();
+            if (organizationName != null) {
+                mDisclosure.switchIndication(mContext.getResources().getString(
+                        R.string.do_disclosure_with_name, organizationName));
+            } else {
+                mDisclosure.switchIndication(R.string.do_disclosure_generic);
+            }
+            mDisclosure.setVisibility(View.VISIBLE);
+        } else {
+            mDisclosure.setVisibility(View.GONE);
+        }
+    }
+
     public void setVisible(boolean visible) {
         mVisible = visible;
         mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -574,6 +622,11 @@
     }
 
     @Override
+    public void onDozeAmountChanged(float linear, float eased) {
+        mDisclosure.setAlpha((1 - linear) * mDisclosureMaxAlpha);
+    }
+
+    @Override
     public void onUnlockedChanged() {
         updateIndication(!mDozing);
     }
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 5ee4693..e0532c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -17,9 +17,11 @@
 package com.android.systemui.statusbar.notification;
 
 import android.content.res.Resources;
+import android.text.Layout;
 import android.util.Pools;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.TextView;
 
 import com.android.internal.widget.IMessagingLayout;
 import com.android.internal.widget.MessagingGroup;
@@ -229,6 +231,15 @@
         return result;
     }
 
+    private boolean hasEllipses(TextView textView) {
+        Layout layout = textView.getLayout();
+        return layout != null && layout.getEllipsisCount(layout.getLineCount() - 1) > 0;
+    }
+
+    private boolean needsReflow(TextView own, TextView other) {
+        return hasEllipses(own) != hasEllipses(other);
+    }
+
     /**
      * Transform two groups towards each other.
      *
@@ -238,13 +249,20 @@
             float transformationAmount, boolean to) {
         boolean useLinearTransformation =
                 otherGroup.getIsolatedMessage() == null && !mTransformInfo.isAnimating();
-        transformView(transformationAmount, to, ownGroup.getSenderView(), otherGroup.getSenderView(),
-                true /* sameAsAny */, useLinearTransformation);
+        TextView ownSenderView = ownGroup.getSenderView();
+        TextView otherSenderView = otherGroup.getSenderView();
+        transformView(transformationAmount, to, ownSenderView, otherSenderView,
+                // Normally this would be handled by the TextViewMessageState#sameAs check, but in
+                // this case it doesn't work because our text won't match, due to the appended colon
+                // in the collapsed view.
+                !needsReflow(ownSenderView, otherSenderView),
+                useLinearTransformation);
         int totalAvatarTranslation = transformView(transformationAmount, to, ownGroup.getAvatar(),
                 otherGroup.getAvatar(), true /* sameAsAny */, useLinearTransformation);
         List<MessagingMessage> ownMessages = ownGroup.getMessages();
         List<MessagingMessage> otherMessages = otherGroup.getMessages();
         float previousTranslation = 0;
+        boolean isLastView = true;
         for (int i = 0; i < ownMessages.size(); i++) {
             View child = ownMessages.get(ownMessages.size() - 1 - i).getView();
             if (isGone(child)) {
@@ -278,6 +296,9 @@
                 mMessagingLayout.setMessagingClippingDisabled(true);
             }
             if (otherChild == null) {
+                if (isLastView) {
+                    previousTranslation = ownSenderView.getTranslationY();
+                }
                 child.setTranslationY(previousTranslation);
                 setClippingDeactivated(child, true);
             } else if (ownGroup.getIsolatedMessage() == child || otherIsIsolated) {
@@ -287,6 +308,7 @@
             } else {
                 previousTranslation = child.getTranslationY();
             }
+            isLastView = false;
         }
         ownGroup.updateClipRect();
         return totalAvatarTranslation;
@@ -382,6 +404,9 @@
         if (view.getParent() == null) {
             return true;
         }
+        if (view.getWidth() == 0) {
+            return true;
+        }
         final ViewGroup.LayoutParams lp = view.getLayoutParams();
         if (lp instanceof MessagingLinearLayout.LayoutParams
                 && ((MessagingLinearLayout.LayoutParams) lp).hide) {
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 978394c..cad1c91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -17,7 +17,11 @@
 
 import static android.view.Display.INVALID_DISPLAY;
 
+import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
@@ -75,6 +79,8 @@
 import com.android.systemui.tracing.nano.SystemUiTraceProto;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
@@ -121,9 +127,18 @@
         }
     };
 
+    private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+        @Override
+        public void onTaskStackChanged() {
+            mGestureBlockingActivityRunning = isGestureBlockingActivityRunning();
+        }
+    };
+
     private final Context mContext;
     private final OverviewProxyService mOverviewProxyService;
-    private PluginManager mPluginManager;
+    private final PluginManager mPluginManager;
+    // Activities which should not trigger Back gesture.
+    private final List<ComponentName> mGestureBlockingActivities = new ArrayList<>();
 
     private final Point mDisplaySize = new Point();
     private final int mDisplayId;
@@ -162,6 +177,7 @@
     private boolean mIsEnabled;
     private boolean mIsNavBarShownTransiently;
     private boolean mIsBackGestureAllowed;
+    private boolean mGestureBlockingActivityRunning;
 
     private InputMonitor mInputMonitor;
     private InputEventReceiver mInputEventReceiver;
@@ -203,6 +219,29 @@
         mMainExecutor = context.getMainExecutor();
         mOverviewProxyService = overviewProxyService;
         mPluginManager = pluginManager;
+        ComponentName recentsComponentName = ComponentName.unflattenFromString(
+                context.getString(com.android.internal.R.string.config_recentsComponentName));
+        if (recentsComponentName != null) {
+            String recentsPackageName = recentsComponentName.getPackageName();
+            PackageManager manager = context.getPackageManager();
+            try {
+                Resources resources = manager.getResourcesForApplication(recentsPackageName);
+                int resId = resources.getIdentifier(
+                        "gesture_blocking_activities", "array", recentsPackageName);
+
+                if (resId == 0) {
+                    Log.e(TAG, "No resource found for gesture-blocking activities");
+                } else {
+                    String[] gestureBlockingActivities = resources.getStringArray(resId);
+                    for (String gestureBlockingActivity : gestureBlockingActivities) {
+                        mGestureBlockingActivities.add(
+                                ComponentName.unflattenFromString(gestureBlockingActivity));
+                    }
+                }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Failed to add gesture blocking activities", e);
+            }
+        }
         Dependency.get(ProtoTracer.class).add(this);
 
         mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
@@ -324,6 +363,7 @@
             mGestureNavigationSettingsObserver.unregister();
             mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
             mPluginManager.removePluginListener(this);
+            ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
 
             try {
                 WindowManagerGlobal.getWindowManagerService()
@@ -338,6 +378,7 @@
             updateDisplaySize();
             mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
                     mContext.getMainThreadHandler());
+            ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
             try {
                 WindowManagerGlobal.getWindowManagerService()
@@ -491,6 +532,7 @@
             mLogGesture = false;
             mInRejectedExclusion = false;
             mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed
+                    && !mGestureBlockingActivityRunning
                     && !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
                     && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
             if (mAllowGesture) {
@@ -633,6 +675,13 @@
         pw.println("  mEdgeWidthRight=" + mEdgeWidthRight);
     }
 
+    private boolean isGestureBlockingActivityRunning() {
+        ActivityManager.RunningTaskInfo runningTask =
+                ActivityManagerWrapper.getInstance().getRunningTask();
+        ComponentName topActivity = runningTask == null ? null : runningTask.topActivity;
+        return topActivity != null && mGestureBlockingActivities.contains(topActivity);
+    }
+
     @Override
     public void writeToProto(SystemUiTraceProto proto) {
         if (proto.edgeBackGestureHandler == null) {
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 ae7867d..b47c59a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -125,6 +125,7 @@
     private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
     private ViewGroup mIndicationArea;
+    private TextView mEnterpriseDisclosure;
     private TextView mIndicationText;
     private ViewGroup mPreviewContainer;
     private ViewGroup mOverlayContainer;
@@ -238,6 +239,8 @@
         mRightAffordanceView = findViewById(R.id.camera_button);
         mLeftAffordanceView = findViewById(R.id.left_button);
         mIndicationArea = findViewById(R.id.keyguard_indication_area);
+        mEnterpriseDisclosure = findViewById(
+                R.id.keyguard_indication_enterprise_disclosure);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
@@ -315,6 +318,9 @@
         }
 
         // Respect font size setting.
+        mEnterpriseDisclosure.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.text_size_small_material));
         mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                 getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.text_size_small_material));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
index 83d398d..0d6597f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -39,7 +39,7 @@
 public class LockscreenGestureLogger {
 
     /**
-     * Contains Lockscreen related Westworld UiEvent enums.
+     * Contains Lockscreen related statsd UiEvent enums.
      */
     public enum LockscreenUiEvent implements UiEventLogger.UiEventEnum {
         @UiEvent(doc = "Lockscreen > Pull shade open")
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt b/packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt
index ecd3afd..a284a74 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/FloatProperties.kt
@@ -67,6 +67,40 @@
         }
 
         /**
+         * Represents the width of a [Rect]. Typically used to animate resizing a Rect horizontally.
+         *
+         * This property's getter returns [Rect.width], and its setter changes the value of
+         * [Rect.right] by adding the animated width value to [Rect.left].
+         */
+        @JvmField
+        val RECT_WIDTH = object : FloatPropertyCompat<Rect>("RectWidth") {
+            override fun getValue(rect: Rect): Float {
+                return rect.width().toFloat()
+            }
+
+            override fun setValue(rect: Rect, value: Float) {
+                rect.right = rect.left + value.toInt()
+            }
+        }
+
+        /**
+         * Represents the height of a [Rect]. Typically used to animate resizing a Rect vertically.
+         *
+         * This property's getter returns [Rect.height], and its setter changes the value of
+         * [Rect.bottom] by adding the animated height value to [Rect.top].
+         */
+        @JvmField
+        val RECT_HEIGHT = object : FloatPropertyCompat<Rect>("RectHeight") {
+            override fun getValue(rect: Rect): Float {
+                return rect.height().toFloat()
+            }
+
+            override fun setValue(rect: Rect, value: Float) {
+                rect.bottom = rect.top + value.toInt()
+            }
+        }
+
+        /**
          * Represents the x-coordinate of a [RectF]. Typically used to animate moving a RectF
          * horizontally.
          *
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
index eeca1e3..e5b126d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.util.animation
 
 import android.content.Context
+import android.graphics.Canvas
 import android.graphics.PointF
 import android.graphics.Rect
 import android.util.AttributeSet
@@ -37,6 +38,7 @@
     defStyleAttr: Int = 0
 ) : ConstraintLayout(context, attrs, defStyleAttr) {
 
+    private val boundsRect = Rect()
     private val originalGoneChildrenSet: MutableSet<Int> = mutableSetOf()
     private val originalViewAlphas: MutableMap<Int, Float> = mutableMapOf()
     private var measureAsConstraint: Boolean = false
@@ -147,16 +149,26 @@
         }
     }
 
+    override fun dispatchDraw(canvas: Canvas?) {
+        val clip = !boundsRect.isEmpty
+        if (clip) {
+            canvas?.save()
+            canvas?.clipRect(boundsRect)
+        }
+        super.dispatchDraw(canvas)
+        if (clip) {
+            canvas?.restore()
+        }
+    }
+
     private fun updateBounds() {
         val layoutLeft = left
         val layoutTop = top
         setLeftTopRightBottom(layoutLeft, layoutTop, layoutLeft + currentState.width,
                 layoutTop + currentState.height)
-        val bounds = clipBounds ?: Rect()
-        bounds.set(left, top, right, bottom)
-        clipBounds = bounds
         translationX = currentState.translation.x
         translationY = currentState.translation.y
+        boundsRect.set(0, 0, (width + translationX).toInt(), (height + translationY).toInt())
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index 5a2b064..47b607f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -178,6 +178,18 @@
     var physicsAnimatorEndListener: PhysicsAnimator.EndListener<T>? = null
 
     /**
+     * Method that is called when the object should be animated stuck to the target. The default
+     * implementation uses the object's x and y properties to animate the object centered inside the
+     * target. You can override this if you need custom animation.
+     *
+     * The method is invoked with the MagneticTarget that the object is sticking to, the X and Y
+     * velocities of the gesture that brought the object into the magnetic radius, whether or not it
+     * was flung, and a callback you must call after your animation completes.
+     */
+    var animateStuckToTarget: (MagneticTarget, Float, Float, Boolean, (() -> Unit)?) -> Unit =
+            ::animateStuckToTargetInternal
+
+    /**
      * Sets whether forcefully flinging the object vertically towards a target causes it to be
      * attracted to the target and then released immediately, despite never being dragged within the
      * magnetic field.
@@ -373,7 +385,7 @@
             targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
             cancelAnimations()
             magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
-            animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false)
+            animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false, null)
 
             vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
         } else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
@@ -430,8 +442,8 @@
                 targetObjectIsStuckTo = flungToTarget
 
                 animateStuckToTarget(flungToTarget, velX, velY, true) {
-                    targetObjectIsStuckTo = null
                     magnetListener.onReleasedInTarget(flungToTarget)
+                    targetObjectIsStuckTo = null
                     vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
                 }
 
@@ -465,7 +477,7 @@
     }
 
     /** Animates sticking the object to the provided target with the given start velocities.  */
-    private fun animateStuckToTarget(
+    private fun animateStuckToTargetInternal(
         target: MagneticTarget,
         velX: Float,
         velY: Float,
@@ -581,10 +593,10 @@
      * multiple objects.
      */
     class MagneticTarget(
-        internal val targetView: View,
+        val targetView: View,
         var magneticFieldRadiusPx: Int
     ) {
-        internal val centerOnScreen = PointF()
+        val centerOnScreen = PointF()
 
         private val tempLoc = IntArray(2)
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 6131e3b..369552f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -340,7 +340,7 @@
     }
 
     /**
-     * Logs an event to the event log and UiEvent (Westworld) logging. Compare writeEvent, which
+     * Logs an event to the event log and UiEvent (statsd) logging. Compare writeEvent, which
      * adds more log destinations.
      * @param tag One of the EVENT_* codes above.
      * @param list Any additional event-specific arguments, documented above.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 59f8c4e..36398a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -304,6 +304,10 @@
     public void testPromoteBubble_autoExpand() throws Exception {
         mBubbleController.updateBubble(mRow2.getEntry());
         mBubbleController.updateBubble(mRow.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+                .thenReturn(mRow.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
+                .thenReturn(mRow2.getEntry());
         mBubbleController.removeBubble(
                 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
 
@@ -331,6 +335,10 @@
         mBubbleController.updateBubble(mRow2.getEntry());
         mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
                 false, /* showInShade */ true);
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+                .thenReturn(mRow.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
+                .thenReturn(mRow2.getEntry());
         mBubbleController.removeBubble(
                 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
 
@@ -433,15 +441,16 @@
         assertTrue(mSysUiStateBubblesExpanded);
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
+        assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry()));
 
         // Switch which bubble is expanded
-        mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
+        mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
+                mRow.getEntry().getKey()));
         mBubbleData.setExpanded(true);
-        assertEquals(mRow.getEntry(),
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+        assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+                stackView.getExpandedBubble().getKey()).getKey());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
 
@@ -543,27 +552,27 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(),
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+        assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+                stackView.getExpandedBubble().getKey()).getKey());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry()));
 
         // Dismiss currently expanded
         mBubbleController.removeBubble(
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey())
-                        .getEntry().getKey(),
+                mBubbleData.getBubbleInStackWithKey(
+                        stackView.getExpandedBubble().getKey()).getKey(),
                 BubbleController.DISMISS_USER_GESTURE);
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
 
         // Make sure first bubble is selected
-        assertEquals(mRow.getEntry(),
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+        assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+                stackView.getExpandedBubble().getKey()).getKey());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
         // Dismiss that one
         mBubbleController.removeBubble(
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey())
-                        .getEntry().getKey(),
+                mBubbleData.getBubbleInStackWithKey(
+                        stackView.getExpandedBubble().getKey()).getKey(),
                 BubbleController.DISMISS_USER_GESTURE);
 
         // Make sure state changes and collapse happens
@@ -839,6 +848,12 @@
                 mRow2.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
         mBubbleController.updateBubble(
                 mRow3.getEntry(), /* suppressFlyout */ false, /* showInShade */ false);
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+                .thenReturn(mRow.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
+                .thenReturn(mRow2.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow3.getEntry().getKey()))
+                .thenReturn(mRow3.getEntry());
         assertEquals(mBubbleData.getBubbles().size(), 3);
 
         mBubbleData.setMaxOverflowBubbles(1);
@@ -908,6 +923,8 @@
         // GIVEN a group summary with a bubble child
         ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
         ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+        when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+                .thenReturn(groupedBubble.getEntry());
         mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
         groupSummary.addChildNotification(groupedBubble);
         assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
@@ -927,6 +944,8 @@
         ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
         ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
         mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+                .thenReturn(groupedBubble.getEntry());
         groupSummary.addChildNotification(groupedBubble);
         assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
 
@@ -948,6 +967,8 @@
         // GIVEN a group summary with two (non-bubble) children and one bubble child
         ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
         ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
+        when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+                .thenReturn(groupedBubble.getEntry());
         mEntryListener.onPendingEntryAdded(groupedBubble.getEntry());
         groupSummary.addChildNotification(groupedBubble);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
index 72f816f..be03923 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
@@ -86,8 +86,7 @@
         final String msg = "Hello there!";
         doReturn(Notification.Style.class).when(mNotif).getNotificationStyle();
         mExtras.putCharSequence(Notification.EXTRA_TEXT, msg);
-        assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
-                mEntry).message);
+        assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
     }
 
     @Test
@@ -98,8 +97,7 @@
         mExtras.putCharSequence(Notification.EXTRA_BIG_TEXT, msg);
 
         // Should be big text, not the small text.
-        assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
-                mEntry).message);
+        assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
     }
 
     @Test
@@ -107,8 +105,7 @@
         doReturn(Notification.MediaStyle.class).when(mNotif).getNotificationStyle();
 
         // Media notifs don't get update messages.
-        assertNull(BubbleViewInfoTask.extractFlyoutMessage(mContext,
-                mEntry).message);
+        assertNull(BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
     }
 
     @Test
@@ -124,7 +121,7 @@
 
         // Should be the last one only.
         assertEquals("Really? I prefer them that way.",
-                BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
+                BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
     }
 
     @Test
@@ -139,11 +136,8 @@
                                 "Oh, hello!", 0, "Mady").toBundle()});
 
         // Should be the last one only.
-        assertEquals("Oh, hello!",
-                BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
-        assertEquals("Mady",
-                BubbleViewInfoTask.extractFlyoutMessage(mContext,
-                        mEntry).senderName);
+        assertEquals("Oh, hello!", BubbleViewInfoTask.extractFlyoutMessage(mEntry).message);
+        assertEquals("Mady", BubbleViewInfoTask.extractFlyoutMessage(mEntry).senderName);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 58e06b5..1c70db3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -302,6 +302,8 @@
     public void testRemoveBubble_withDismissedNotif_notInOverflow() {
         mEntryListener.onEntryAdded(mRow.getEntry());
         mBubbleController.updateBubble(mRow.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
+                .thenReturn(mRow.getEntry());
 
         assertTrue(mBubbleController.hasBubbles());
         assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
@@ -388,14 +390,14 @@
                 true, mRow.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
+        assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
 
         // Switch which bubble is expanded
         mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
         mBubbleData.setExpanded(true);
-        assertEquals(mRow.getEntry(),
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+        assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+                stackView.getExpandedBubble().getKey()).getKey());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
 
@@ -488,27 +490,27 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(),
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+        assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+                stackView.getExpandedBubble().getKey()).getKey());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry()));
 
         // Dismiss currently expanded
         mBubbleController.removeBubble(
                 mBubbleData.getBubbleInStackWithKey(
-                        stackView.getExpandedBubble().getKey()).getEntry().getKey(),
+                        stackView.getExpandedBubble().getKey()).getKey(),
                 BubbleController.DISMISS_USER_GESTURE);
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
 
         // Make sure first bubble is selected
-        assertEquals(mRow.getEntry(),
-                mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry());
+        assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
+                stackView.getExpandedBubble().getKey()).getKey());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
         // Dismiss that one
         mBubbleController.removeBubble(
                 mBubbleData.getBubbleInStackWithKey(
-                        stackView.getExpandedBubble().getKey()).getEntry().getKey(),
+                        stackView.getExpandedBubble().getKey()).getKey(),
                 BubbleController.DISMISS_USER_GESTURE);
 
         // Make sure state changes and collapse happens
@@ -767,6 +769,8 @@
         ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
         ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
         mEntryListener.onEntryAdded(groupedBubble.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+                .thenReturn(groupedBubble.getEntry());
         groupSummary.addChildNotification(groupedBubble);
         assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
 
@@ -785,6 +789,8 @@
         ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
         ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
         mEntryListener.onEntryAdded(groupedBubble.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+                .thenReturn(groupedBubble.getEntry());
         groupSummary.addChildNotification(groupedBubble);
         assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
 
@@ -807,6 +813,8 @@
         ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
         ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
         mEntryListener.onEntryAdded(groupedBubble.getEntry());
+        when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
+                .thenReturn(groupedBubble.getEntry());
         groupSummary.addChildNotification(groupedBubble);
 
         // WHEN the summary is dismissed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
index 1d02b8d..9b8fd11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -32,7 +32,7 @@
 
     private val bubbles = listOf(
             BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
-            BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428),
+            BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title"),
             BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
     )
     private lateinit var repository: BubblePersistentRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
index f9d611c..76c5833 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -37,9 +37,10 @@
     private val user0 = UserHandle.of(0)
     private val user10 = UserHandle.of(10)
 
-    private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1", 120, 0)
-    private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2", 0, 16537428)
-    private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3", 120, 0)
+    private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0)
+    private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
+            "key-2", 0, 16537428, "title")
+    private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
 
     private val bubbles = listOf(bubble1, bubble2, bubble3)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
index 4946787..81687c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
@@ -31,17 +31,17 @@
 class BubbleXmlHelperTest : SysuiTestCase() {
 
     private val bubbles = listOf(
-        BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
-        BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428),
-        BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
+            BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
+            BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title"),
+            BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
     )
 
     @Test
     fun testWriteXml() {
         val expectedEntries = """
-            <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
-            <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
-            <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
         """.trimIndent()
         ByteArrayOutputStream().use {
             writeXml(it, bubbles)
@@ -54,12 +54,12 @@
     @Test
     fun testReadXml() {
         val src = """
-            <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-            <bs>
-            <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
-            <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
-            <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
-            </bs>
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<bs>
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+</bs>
         """.trimIndent()
         val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
         assertEquals("failed parsing bubbles from xml\n$src", bubbles, actual)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index 082c8ba..916fd0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -38,6 +38,7 @@
 import org.mockito.Mockito
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
@@ -99,6 +100,10 @@
 
     @Test
     fun testOnMediaDataLoaded_registersPlaybackListener() {
+        val playingState = mock(android.media.session.PlaybackState::class.java)
+        `when`(playingState.state).thenReturn(PlaybackState.STATE_PLAYING)
+
+        `when`(mediaController.playbackState).thenReturn(playingState)
         mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
         verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
 
@@ -109,6 +114,13 @@
     }
 
     @Test
+    fun testOnMediaDataLoaded_registersTimeout_whenPaused() {
+        mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
+        verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
+        verify(executor).executeDelayed(capture(timeoutCaptor), anyLong())
+    }
+
+    @Test
     fun testOnMediaDataRemoved_unregistersPlaybackListener() {
         mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
         mediaTimeoutListener.onMediaDataRemoved(KEY)
@@ -165,4 +177,4 @@
         mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
         assertThat(mediaTimeoutListener.isTimedOut(KEY)).isFalse()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 23099d7..22f50d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -25,17 +25,21 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.face.FaceManager;
@@ -44,6 +48,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.view.View;
 import android.view.ViewGroup;
 
 import androidx.test.InstrumentationRegistry;
@@ -52,13 +57,16 @@
 
 import com.android.internal.app.IBatteryStats;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.Utils;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+import com.android.systemui.statusbar.phone.LockIcon;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.wakelock.WakeLockFake;
@@ -75,6 +83,10 @@
 @RunWith(AndroidJUnit4.class)
 public class KeyguardIndicationControllerTest extends SysuiTestCase {
 
+    private static final String ORGANIZATION_NAME = "organization";
+
+    private String mDisclosureWithOrganization;
+
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
@@ -82,6 +94,12 @@
     @Mock
     private KeyguardStateController mKeyguardStateController;
     @Mock
+    private KeyguardIndicationTextView mDisclosure;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private LockIcon mLockIcon;
+    @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -112,11 +130,17 @@
         mContext.addMockSystemService(UserManager.class, mUserManager);
         mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
         mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
+        mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
+                ORGANIZATION_NAME);
 
         when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
         when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
+
+        when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
+                .thenReturn(mDisclosure);
         when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
+        when(mDisclosure.getAlpha()).thenReturn(1f);
 
         mWakeLock = new WakeLockFake();
         mWakeLockBuilder = new WakeLockFake.Builder(mContext);
@@ -130,10 +154,11 @@
 
         mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
                 mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
-                mDockManager, mIBatteryStats);
+                mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats);
         mController.setIndicationArea(mIndicationArea);
         mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         clearInvocations(mIBatteryStats);
+        verify(mDisclosure).getAlpha();
     }
 
     @Test
@@ -215,6 +240,106 @@
     }
 
     @Test
+    public void disclosure_unmanaged() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        createController();
+
+        verify(mDisclosure).setVisibility(View.GONE);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void disclosure_managedNoOwnerName() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+        createController();
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void disclosure_hiddenWhenDozing() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+        createController();
+
+        mController.setVisible(true);
+        mController.onDozeAmountChanged(1, 1);
+        mController.setDozing(true);
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).setAlpha(0f);
+        verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void disclosure_visibleWhenDozing() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+        createController();
+
+        mController.setVisible(true);
+        mController.onDozeAmountChanged(0, 0);
+        mController.setDozing(false);
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).setAlpha(1f);
+        verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void disclosure_managedOwnerName() {
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+        createController();
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
+    public void disclosure_updateOnTheFly() {
+        ArgumentCaptor<BroadcastReceiver> receiver = ArgumentCaptor.forClass(
+                BroadcastReceiver.class);
+        doNothing().when(mBroadcastDispatcher).registerReceiver(receiver.capture(), any());
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        createController();
+
+        final KeyguardUpdateMonitorCallback monitor = mController.getKeyguardCallback();
+        reset(mDisclosure);
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+        receiver.getValue().onReceive(mContext, new Intent());
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+        verifyNoMoreInteractions(mDisclosure);
+        reset(mDisclosure);
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+        receiver.getValue().onReceive(mContext, new Intent());
+
+        verify(mDisclosure).setVisibility(View.VISIBLE);
+        verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
+        verifyNoMoreInteractions(mDisclosure);
+        reset(mDisclosure);
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+        receiver.getValue().onReceive(mContext, new Intent());
+
+        verify(mDisclosure).setVisibility(View.GONE);
+        verifyNoMoreInteractions(mDisclosure);
+    }
+
+    @Test
     public void transientIndication_holdsWakeLock_whenDozing() {
         createController();
 
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index fd6f171..f14def6a 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -37,8 +37,8 @@
     private TetheringConstants() { }
 
     /**
-     * Extra used for communicating with the TetherService. Includes the type of tethering to
-     * enable if any.
+     * Extra used for communicating with the TetherService and TetherProvisioningActivity.
+     * Includes the type of tethering to enable if any.
      */
     public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
     /**
@@ -56,8 +56,38 @@
      */
     public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
     /**
-     * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
-     * which will receive provisioning results. Can be left empty.
+     * Extra used for communicating with the TetherService and TetherProvisioningActivity.
+     * Contains the {@link ResultReceiver} which will receive provisioning results.
+     * Can not be empty.
      */
     public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+
+    /**
+     * Extra used for communicating with the TetherService and TetherProvisioningActivity.
+     * Contains the subId of current active cellular upstream.
+     * @hide
+     */
+    public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID";
+
+    /**
+     * Extra used for telling TetherProvisioningActivity the entitlement package name and class
+     * name to start UI entitlement check.
+     * @hide
+     */
+    public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME =
+            "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME";
+
+    /**
+     * Extra used for telling TetherService the intent action to start silent entitlement check.
+     * @hide
+     */
+    public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION =
+            "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION";
+
+    /**
+     * Extra used for TetherService to receive the response of provisioning check.
+     * @hide
+     */
+    public static final String EXTRA_TETHER_PROVISIONING_RESPONSE =
+            "android.net.extra.TETHER_PROVISIONING_RESPONSE";
 }
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 3c6e8d8..9dace70 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -19,6 +19,10 @@
 import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
 import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
 import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
+import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE;
+import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION;
+import static android.net.TetheringConstants.EXTRA_TETHER_SUBID;
+import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME;
 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
 import static android.net.TetheringManager.TETHERING_ETHERNET;
 import static android.net.TetheringManager.TETHERING_INVALID;
@@ -69,7 +73,6 @@
     protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
     private static final String ACTION_PROVISIONING_ALARM =
             "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
-    private static final String EXTRA_SUBID = "subId";
 
     private final ComponentName mSilentProvisioningService;
     private static final int MS_PER_HOUR = 60 * 60 * 1000;
@@ -197,9 +200,9 @@
         // till upstream change to cellular.
         if (mUsingCellularAsUpstream) {
             if (showProvisioningUi) {
-                runUiTetherProvisioning(downstreamType, config.activeDataSubId);
+                runUiTetherProvisioning(downstreamType, config);
             } else {
-                runSilentTetherProvisioning(downstreamType, config.activeDataSubId);
+                runSilentTetherProvisioning(downstreamType, config);
             }
             mNeedReRunProvisioningUi = false;
         } else {
@@ -262,9 +265,9 @@
             if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
                 if (mNeedReRunProvisioningUi) {
                     mNeedReRunProvisioningUi = false;
-                    runUiTetherProvisioning(downstream, config.activeDataSubId);
+                    runUiTetherProvisioning(downstream, config);
                 } else {
-                    runSilentTetherProvisioning(downstream, config.activeDataSubId);
+                    runSilentTetherProvisioning(downstream, config);
                 }
             }
         }
@@ -361,7 +364,7 @@
      * @param subId default data subscription ID.
      */
     @VisibleForTesting
-    protected void runSilentTetherProvisioning(int type, int subId) {
+    protected Intent runSilentTetherProvisioning(int type, final TetheringConfiguration config) {
         if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
         // For silent provisioning, settings would stop tethering when entitlement fail.
         ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
@@ -369,17 +372,20 @@
         Intent intent = new Intent();
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
         intent.putExtra(EXTRA_RUN_PROVISION, true);
+        intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, config.provisioningAppNoUi);
+        intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, config.provisioningResponse);
         intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
-        intent.putExtra(EXTRA_SUBID, subId);
+        intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId);
         intent.setComponent(mSilentProvisioningService);
         // Only admin user can change tethering and SilentTetherProvisioning don't need to
         // show UI, it is fine to always start setting's background service as system user.
         mContext.startService(intent);
+        return intent;
     }
 
-    private void runUiTetherProvisioning(int type, int subId) {
+    private void runUiTetherProvisioning(int type, final TetheringConfiguration config) {
         ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
-        runUiTetherProvisioning(type, subId, receiver);
+        runUiTetherProvisioning(type, config, receiver);
     }
 
     /**
@@ -389,17 +395,20 @@
      * @param receiver to receive entitlement check result.
      */
     @VisibleForTesting
-    protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
+    protected Intent runUiTetherProvisioning(int type, final TetheringConfiguration config,
+            ResultReceiver receiver) {
         if (DBG) mLog.i("runUiTetherProvisioning: " + type);
 
         Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI);
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, config.provisioningApp);
         intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
-        intent.putExtra(EXTRA_SUBID, subId);
+        intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         // Only launch entitlement UI for system user. Entitlement UI should not appear for other
         // user because only admin user is allowed to change tethering.
         mContext.startActivity(intent);
+        return intent;
     }
 
     // Not needed to check if this don't run on the handler thread because it's private.
@@ -631,7 +640,7 @@
             receiver.send(cacheValue, null);
         } else {
             ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
-            runUiTetherProvisioning(downstream, config.activeDataSubId, proxy);
+            runUiTetherProvisioning(downstream, config, proxy);
         }
     }
 }
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index df67458..2f01186 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
@@ -70,6 +71,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
 import android.net.EthernetManager;
@@ -109,7 +111,6 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceSpecificException;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -782,11 +783,30 @@
         }
     }
 
+    private boolean isProvisioningNeededButUnavailable() {
+        return isTetherProvisioningRequired() && !doesEntitlementPackageExist();
+    }
+
     boolean isTetherProvisioningRequired() {
         final TetheringConfiguration cfg = mConfig;
         return mEntitlementMgr.isTetherProvisioningRequired(cfg);
     }
 
+    private boolean doesEntitlementPackageExist() {
+        // provisioningApp must contain package and class name.
+        if (mConfig.provisioningApp.length != 2) {
+            return false;
+        }
+
+        final PackageManager pm = mContext.getPackageManager();
+        try {
+            pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
     // TODO: Figure out how to update for local hotspot mode interfaces.
     private void sendTetherStateChangedBroadcast() {
         if (!isTetheringSupported()) return;
@@ -2145,14 +2165,14 @@
     // gservices could set the secure setting to 1 though to enable it on a build where it
     // had previously been turned off.
     boolean isTetheringSupported() {
-        final int defaultVal =
-                SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+        final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
         final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
         final boolean tetherEnabledInSettings = tetherSupported
                 && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
 
-        return tetherEnabledInSettings && hasTetherableConfiguration();
+        return tetherEnabledInSettings && hasTetherableConfiguration()
+                && !isProvisioningNeededButUnavailable();
     }
 
     void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 48a600d..1d45f12 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -107,6 +107,7 @@
     public final String[] provisioningApp;
     public final String provisioningAppNoUi;
     public final int provisioningCheckPeriod;
+    public final String provisioningResponse;
 
     public final int activeDataSubId;
 
@@ -141,10 +142,13 @@
         enableLegacyDhcpServer = getEnableLegacyDhcpServer(res);
 
         provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app);
-        provisioningAppNoUi = getProvisioningAppNoUi(res);
+        provisioningAppNoUi = getResourceString(res,
+                R.string.config_mobile_hotspot_provision_app_no_ui);
         provisioningCheckPeriod = getResourceInteger(res,
                 R.integer.config_mobile_hotspot_provision_check_period,
                 0 /* No periodic re-check */);
+        provisioningResponse = getResourceString(res,
+                R.string.config_mobile_hotspot_provision_response);
 
         mOffloadPollInterval = getResourceInteger(res,
                 R.integer.config_tether_offload_poll_interval,
@@ -337,9 +341,9 @@
         return copy(LEGACY_DHCP_DEFAULT_RANGE);
     }
 
-    private static String getProvisioningAppNoUi(Resources res) {
+    private static String getResourceString(Resources res, final int resId) {
         try {
-            return res.getString(R.string.config_mobile_hotspot_provision_app_no_ui);
+            return res.getString(resId);
         } catch (Resources.NotFoundException e) {
             return "";
         }
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index d637c86..31f747d 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -26,6 +26,8 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.SystemProperties;
+import android.text.TextUtils;
 
 import androidx.annotation.NonNull;
 
@@ -150,4 +152,11 @@
      * Get a reference to BluetoothAdapter to be used by tethering.
      */
     public abstract BluetoothAdapter getBluetoothAdapter();
+
+    /**
+     * Get SystemProperties which indicate whether tethering is denied.
+     */
+    public boolean isTetheringDenied() {
+        return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true");
+    }
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index 72fa916..354e753 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -16,8 +16,16 @@
 
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
+import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE;
+import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION;
+import static android.net.TetheringConstants.EXTRA_TETHER_SUBID;
+import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME;
 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
 import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_INVALID;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
@@ -44,6 +52,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.net.util.SharedLog;
 import android.os.Bundle;
@@ -53,6 +62,7 @@
 import android.os.SystemProperties;
 import android.os.test.TestLooper;
 import android.provider.DeviceConfig;
+import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 
 import androidx.test.filters.SmallTest;
@@ -76,6 +86,7 @@
 
     private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
     private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
+    private static final String PROVISIONING_APP_RESPONSE = "app_response";
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
     @Mock private Context mContext;
@@ -122,15 +133,51 @@
         }
 
         @Override
-        protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
+        protected Intent runUiTetherProvisioning(int type,
+                final TetheringConfiguration config, final ResultReceiver receiver) {
+            Intent intent = super.runUiTetherProvisioning(type, config, receiver);
+            assertUiTetherProvisioningIntent(type, config, receiver, intent);
             uiProvisionCount++;
             receiver.send(fakeEntitlementResult, null);
+            return intent;
+        }
+
+        private void assertUiTetherProvisioningIntent(int type, final TetheringConfiguration config,
+                final ResultReceiver receiver, final Intent intent) {
+            assertEquals(Settings.ACTION_TETHER_PROVISIONING_UI, intent.getAction());
+            assertEquals(type, intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID));
+            final String[] appName = intent.getStringArrayExtra(
+                    EXTRA_TETHER_UI_PROVISIONING_APP_NAME);
+            assertEquals(PROVISIONING_APP_NAME.length, appName.length);
+            for (int i = 0; i < PROVISIONING_APP_NAME.length; i++) {
+                assertEquals(PROVISIONING_APP_NAME[i], appName[i]);
+            }
+            assertEquals(receiver, intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK));
+            assertEquals(config.activeDataSubId,
+                    intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID));
         }
 
         @Override
-        protected void runSilentTetherProvisioning(int type, int subId) {
+        protected Intent runSilentTetherProvisioning(int type,
+                final TetheringConfiguration config) {
+            Intent intent = super.runSilentTetherProvisioning(type, config);
+            assertSilentTetherProvisioning(type, config, intent);
             silentProvisionCount++;
             addDownstreamMapping(type, fakeEntitlementResult);
+            return intent;
+        }
+
+        private void assertSilentTetherProvisioning(int type, final TetheringConfiguration config,
+                final Intent intent) {
+            assertEquals(type, intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID));
+            assertEquals(true, intent.getBooleanExtra(EXTRA_RUN_PROVISION, false));
+            assertEquals(PROVISIONING_NO_UI_APP_NAME,
+                    intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION));
+            assertEquals(PROVISIONING_APP_RESPONSE,
+                    intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE));
+            assertTrue(intent.hasExtra(EXTRA_PROVISION_CALLBACK));
+            assertEquals(config.activeDataSubId,
+                    intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID));
         }
     }
 
@@ -187,6 +234,8 @@
                 .thenReturn(PROVISIONING_APP_NAME);
         when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
                 .thenReturn(PROVISIONING_NO_UI_APP_NAME);
+        when(mResources.getString(R.string.config_mobile_hotspot_provision_response)).thenReturn(
+                PROVISIONING_APP_RESPONSE);
         // Act like the CarrierConfigManager is present and ready unless told otherwise.
         when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
                 .thenReturn(mCarrierConfigManager);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index 1999ad7..3121863 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -61,6 +61,8 @@
     private final SharedLog mLog = new SharedLog("TetheringConfigurationTest");
 
     private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+    private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
+    private static final String PROVISIONING_APP_RESPONSE = "app_response";
     @Mock private Context mContext;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private Resources mResources;
@@ -388,6 +390,8 @@
                 new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId);
         assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]);
         assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]);
+        assertEquals(mockCfg.provisioningAppNoUi, PROVISIONING_NO_UI_APP_NAME);
+        assertEquals(mockCfg.provisioningResponse, PROVISIONING_APP_RESPONSE);
     }
 
     private void setUpResourceForSubId() {
@@ -403,6 +407,10 @@
                 new int[0]);
         when(mResourcesForSubId.getStringArray(
                 R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME);
+        when(mResourcesForSubId.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
+                .thenReturn(PROVISIONING_NO_UI_APP_NAME);
+        when(mResourcesForSubId.getString(
+                R.string.config_mobile_hotspot_provision_response)).thenReturn(
+                PROVISIONING_APP_RESPONSE);
     }
-
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 8146a58d..f53c42b 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -16,6 +16,7 @@
 
 package com.android.networkstack.tethering;
 
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
@@ -81,6 +82,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
@@ -204,6 +206,7 @@
     @Mock private EthernetManager mEm;
     @Mock private TetheringNotificationUpdater mNotificationUpdater;
     @Mock private BpfCoordinator mBpfCoordinator;
+    @Mock private PackageManager mPackageManager;
 
     private final MockIpServerDependencies mIpServerDependencies =
             spy(new MockIpServerDependencies());
@@ -264,6 +267,11 @@
         }
 
         @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+
+        @Override
         public String getSystemServiceName(Class<?> serviceClass) {
             if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE;
             return super.getSystemServiceName(serviceClass);
@@ -425,6 +433,11 @@
         public TetheringNotificationUpdater getNotificationUpdater(Context ctx, Looper looper) {
             return mNotificationUpdater;
         }
+
+        @Override
+        public boolean isTetheringDenied() {
+            return false;
+        }
     }
 
     private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4,
@@ -1951,6 +1964,23 @@
         assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastTetherError(TEST_ETH_IFNAME));
     }
 
+    @Test
+    public void testProvisioningNeededButUnavailable() throws Exception {
+        assertTrue(mTethering.isTetheringSupported());
+        verify(mPackageManager, never()).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+
+        setupForRequiredProvisioning();
+        assertTrue(mTethering.isTetheringSupported());
+        verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+        reset(mPackageManager);
+
+        doThrow(PackageManager.NameNotFoundException.class).when(mPackageManager).getPackageInfo(
+                PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+        setupForRequiredProvisioning();
+        assertFalse(mTethering.isTetheringSupported());
+        verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+    }
+
     // TODO: Test that a request for hotspot mode doesn't interfere with an
     // already operating tethering mode interface.
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 96b593d..57ffe04 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -815,6 +815,19 @@
         }
     }
 
+    void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset,
+            @Nullable Bundle clientState) {
+        synchronized (mLock) {
+            if (mAugmentedAutofillEventHistory == null
+                    || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
+                return;
+            }
+            mAugmentedAutofillEventHistory.addEvent(
+                    new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
+                            clientState, null, null, null, null, null, null, null, null));
+        }
+    }
+
     void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
             @Nullable Bundle clientState) {
         synchronized (mLock) {
@@ -1199,6 +1212,14 @@
                         }
 
                         @Override
+                        public void logAugmentedAutofillAuthenticationSelected(int sessionId,
+                                String suggestionId, Bundle clientState) {
+                            AutofillManagerServiceImpl.this
+                                    .logAugmentedAutofillAuthenticationSelected(
+                                            sessionId, suggestionId, clientState);
+                        }
+
+                        @Override
                         public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
                             Slog.w(TAG, "remote augmented autofill service died");
                             final RemoteAugmentedAutofillService remoteService =
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index a7d0061..11f9015 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -167,14 +167,16 @@
                             new IFillCallback.Stub() {
                                 @Override
                                 public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData,
-                                        @Nullable Bundle clientState) {
+                                        @Nullable Bundle clientState, boolean showingFillWindow) {
                                     mCallbacks.resetLastResponse();
                                     maybeRequestShowInlineSuggestions(sessionId,
                                             inlineSuggestionsRequest, inlineSuggestionsData,
                                             clientState, focusedId, focusedValue,
                                             inlineSuggestionsCallback,
                                             client, onErrorCallback, remoteRenderService);
-                                    requestAutofill.complete(null);
+                                    if (!showingFillWindow) {
+                                        requestAutofill.complete(null);
+                                    }
                                 }
 
                                 @Override
@@ -263,7 +265,28 @@
                         request, inlineSuggestionsData, focusedId, filterText,
                         new InlineFillUi.InlineSuggestionUiCallback() {
                             @Override
-                            public void autofill(Dataset dataset) {
+                            public void autofill(Dataset dataset, int datasetIndex) {
+                                if (dataset.getAuthentication() != null) {
+                                    mCallbacks.logAugmentedAutofillAuthenticationSelected(sessionId,
+                                            dataset.getId(), clientState);
+                                    final IntentSender action = dataset.getAuthentication();
+                                    final int authenticationId =
+                                            AutofillManager.makeAuthenticationId(
+                                                    Session.AUGMENTED_AUTOFILL_REQUEST_ID,
+                                                    datasetIndex);
+                                    final Intent fillInIntent = new Intent();
+                                    fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE,
+                                            clientState);
+                                    try {
+                                        client.authenticate(sessionId, authenticationId, action,
+                                                fillInIntent, false);
+                                    } catch (RemoteException e) {
+                                        Slog.w(TAG, "Error starting auth flow");
+                                        inlineSuggestionsCallback.apply(
+                                                InlineFillUi.emptyUi(focusedId));
+                                    }
+                                    return;
+                                }
                                 mCallbacks.logAugmentedAutofillSelected(sessionId,
                                         dataset.getId(), clientState);
                                 try {
@@ -319,5 +342,8 @@
 
         void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
                 @Nullable Bundle clientState);
+
+        void logAugmentedAutofillAuthenticationSelected(int sessionId,
+                @Nullable String suggestionId, @Nullable Bundle clientState);
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index fa449ad..712b413 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -144,7 +144,9 @@
 
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
-    private static AtomicInteger sIdCounter = new AtomicInteger();
+    static final int AUGMENTED_AUTOFILL_REQUEST_ID = 1;
+
+    private static AtomicInteger sIdCounter = new AtomicInteger(2);
 
     /**
      * ID of the session.
@@ -736,7 +738,7 @@
         viewState.setState(newState);
 
         int requestId;
-
+        // TODO(b/158623971): Update this to prevent possible overflow
         do {
             requestId = sIdCounter.getAndIncrement();
         } while (requestId == INVALID_REQUEST_ID);
@@ -1344,6 +1346,11 @@
                     + id + " destroyed");
             return;
         }
+        final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
+        if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) {
+            setAuthenticationResultForAugmentedAutofillLocked(data, authenticationId);
+            return;
+        }
         if (mResponses == null) {
             // Typically happens when app explicitly called cancel() while the service was showing
             // the auth UI.
@@ -1351,7 +1358,6 @@
             removeSelf();
             return;
         }
-        final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
         final FillResponse authenticatedResponse = mResponses.get(requestId);
         if (authenticatedResponse == null || data == null) {
             Slog.w(TAG, "no authenticated response");
@@ -1411,6 +1417,58 @@
     }
 
     @GuardedBy("mLock")
+    void setAuthenticationResultForAugmentedAutofillLocked(Bundle data, int authId) {
+        final Dataset dataset = (data == null) ? null :
+                data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
+        if (sDebug) {
+            Slog.d(TAG, "Auth result for augmented autofill: sessionId=" + id
+                    + ", authId=" + authId + ", dataset=" + dataset);
+        }
+        if (dataset == null
+                || dataset.getFieldIds().size() != 1
+                || dataset.getFieldIds().get(0) == null
+                || dataset.getFieldValues().size() != 1
+                || dataset.getFieldValues().get(0) == null) {
+            if (sDebug) {
+                Slog.d(TAG, "Rejecting empty/invalid auth result");
+            }
+            mService.resetLastAugmentedAutofillResponse();
+            removeSelfLocked();
+            return;
+        }
+        final List<AutofillId> fieldIds = dataset.getFieldIds();
+        final List<AutofillValue> autofillValues = dataset.getFieldValues();
+        final AutofillId fieldId = fieldIds.get(0);
+        final AutofillValue value = autofillValues.get(0);
+
+        // Update state to ensure that after filling the field here we don't end up firing another
+        // autofill request that will end up showing the same suggestions to the user again. When
+        // the auth activity came up, the field for which the suggestions were shown lost focus and
+        // mCurrentViewId was cleared. We need to set mCurrentViewId back to the id of the field
+        // that we are filling.
+        fieldId.setSessionId(id);
+        mCurrentViewId = fieldId;
+
+        // Notify the Augmented Autofill provider of the dataset that was selected.
+        final Bundle clientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
+        mService.logAugmentedAutofillSelected(id, dataset.getId(), clientState);
+
+        // Fill the value into the field.
+        if (sDebug) {
+            Slog.d(TAG, "Filling after auth: fieldId=" + fieldId + ", value=" + value);
+        }
+        try {
+            mClient.autofill(id, fieldIds, autofillValues, true);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error filling after auth: fieldId=" + fieldId + ", value=" + value
+                    + ", error=" + e);
+        }
+
+        // Clear the suggestions since the user already accepted one of them.
+        mInlineSessionController.setInlineFillUiLocked(InlineFillUi.emptyUi(fieldId));
+    }
+
+    @GuardedBy("mLock")
     void setHasCallbackLocked(boolean hasIt) {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: "
@@ -2506,6 +2564,10 @@
                     + actionAsString(action) + ", flags=" + flags);
         }
         ViewState viewState = mViewStates.get(id);
+        if (sVerbose) {
+            Slog.v(TAG, "updateLocked(" + this.id + "): mCurrentViewId=" + mCurrentViewId
+                    + ", mExpiredResponse=" + mExpiredResponse + ", viewState=" + viewState);
+        }
 
         if (viewState == null) {
             if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
@@ -3217,16 +3279,19 @@
                 };
 
         // When the inline suggestion render service is available and the view is focused, there
-        // are 2 cases when augmented autofill should ask IME for inline suggestion request,
+        // are 3 cases when augmented autofill should ask IME for inline suggestion request,
         // because standard autofill flow didn't:
         // 1. the field is augmented autofill only (when standard autofill provider is None or
         // when it returns null response)
         // 2. standard autofill provider doesn't support inline suggestion
+        // 3. we re-entered the autofill session and standard autofill was not re-triggered, this is
+        //    recognized by seeing mExpiredResponse == true
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
         if (remoteRenderService != null
                 && (mForAugmentedAutofillOnly
-                || !isInlineSuggestionsEnabledByAutofillProviderLocked())
+                || !isInlineSuggestionsEnabledByAutofillProviderLocked()
+                || mExpiredResponse)
                 && isViewFocusedLocked(flags)) {
             if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
             remoteRenderService.getInlineSuggestionsRendererInfo(new RemoteCallback(
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
index a3d0fb9..1c430b3 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -290,7 +290,7 @@
         /**
          * Callback to autofill a dataset to the client app.
          */
-        void autofill(@NonNull Dataset dataset);
+        void autofill(@NonNull Dataset dataset, int datasetIndex);
 
         /**
          * Callback to start Intent in client app.
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 c8485b7..462ffd6 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -109,7 +109,7 @@
         return createInlineSuggestionsInternal(/* isAugmented= */ true, request,
                 datasets, autofillId, onErrorCallback,
                 (dataset, datasetIndex) ->
-                        inlineSuggestionUiCallback.autofill(dataset),
+                        inlineSuggestionUiCallback.autofill(dataset, datasetIndex),
                 (intentSender) ->
                         inlineSuggestionUiCallback.startIntentSender(intentSender, new Intent()),
                 remoteRenderService);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2958fd2..36ba610 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1698,6 +1698,12 @@
             return newNc;
         }
 
+        // Allow VPNs to see ownership of their own VPN networks - not location sensitive.
+        if (nc.hasTransport(TRANSPORT_VPN)) {
+            // Owner UIDs already checked above. No need to re-check.
+            return newNc;
+        }
+
         Binder.withCleanCallingIdentity(
                 () -> {
                     if (!mLocationPermissionChecker.checkLocationPermission(
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1ce3dfe..63a984c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3535,6 +3535,13 @@
         // point
         final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM);
 
+        // When the caller is the app actually hosting external storage, we
+        // should never attempt to augment the actual storage volume state,
+        // otherwise we risk confusing it with race conditions as users go
+        // through various unlocked states
+        final boolean callerIsMediaStore = UserHandle.isSameApp(Binder.getCallingUid(),
+                mMediaStoreAuthorityAppId);
+
         final boolean userIsDemo;
         final boolean userKeyUnlocked;
         final boolean storagePermission;
@@ -3554,6 +3561,7 @@
         final ArraySet<String> resUuids = new ArraySet<>();
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
+                final String volId = mVolumes.keyAt(i);
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 switch (vol.getType()) {
                     case VolumeInfo.TYPE_PUBLIC:
@@ -3578,11 +3586,19 @@
                 if (!match) continue;
 
                 boolean reportUnmounted = false;
-                if (!systemUserUnlocked) {
+                if (callerIsMediaStore) {
+                    // When the caller is the app actually hosting external storage, we
+                    // should never attempt to augment the actual storage volume state,
+                    // otherwise we risk confusing it with race conditions as users go
+                    // through various unlocked states
+                } else if (!systemUserUnlocked) {
                     reportUnmounted = true;
+                    Slog.w(TAG, "Reporting " + volId + " unmounted due to system locked");
                 } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
                     reportUnmounted = true;
+                    Slog.w(TAG, "Reporting " + volId + "unmounted due to " + userId + " locked");
                 } else if (!storagePermission && !realState) {
+                    Slog.w(TAG, "Reporting " + volId + "unmounted due to missing permissions");
                     reportUnmounted = true;
                 }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e654af7..1f85d10 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1106,7 +1106,8 @@
         NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
         networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
 
-        mNetworkCapabilities.setOwnerUid(Binder.getCallingUid());
+        mNetworkCapabilities.setOwnerUid(mOwnerUID);
+        mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
         mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
                 mConfig.allowedApplications, mConfig.disallowedApplications));
         long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 769956d..e3eeb6c4 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -47,6 +47,10 @@
 import android.util.Slog;
 import android.view.Display;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
@@ -77,6 +81,8 @@
     private final PowerManagerInternal mPowerManagerInternal;
     private final PowerManager.WakeLock mDozeWakeLock;
     private final ActivityTaskManagerInternal mAtmInternal;
+    private final UiEventLogger mUiEventLogger;
+    private final ComponentName mAmbientDisplayComponent;
 
     private Binder mCurrentDreamToken;
     private ComponentName mCurrentDreamName;
@@ -91,6 +97,26 @@
 
     private AmbientDisplayConfiguration mDozeConfig;
 
+    @VisibleForTesting
+    public enum DreamManagerEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "The screensaver has started.")
+        DREAM_START(577),
+
+        @UiEvent(doc = "The screensaver has stopped.")
+        DREAM_STOP(578);
+
+        private final int mId;
+
+        DreamManagerEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+
     public DreamManagerService(Context context) {
         super(context);
         mContext = context;
@@ -102,6 +128,9 @@
         mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
         mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
         mDozeConfig = new AmbientDisplayConfiguration(mContext);
+        mUiEventLogger = new UiEventLoggerImpl();
+        AmbientDisplayConfiguration adc = new AmbientDisplayConfiguration(mContext);
+        mAmbientDisplayComponent = ComponentName.unflattenFromString(adc.ambientDisplayComponent());
     }
 
     @Override
@@ -388,6 +417,9 @@
                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
         mHandler.post(wakeLock.wrap(() -> {
             mAtmInternal.notifyDreamStateChanged(true);
+            if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
+                mUiEventLogger.log(DreamManagerEvent.DREAM_START);
+            }
             mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock);
         }));
     }
@@ -415,6 +447,9 @@
     }
 
     private void cleanupDreamLocked() {
+        if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
+            mUiEventLogger.log(DreamManagerEvent.DREAM_STOP);
+        }
         mCurrentDreamToken = null;
         mCurrentDreamName = null;
         mCurrentDreamIsTest = false;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b9669c74..87a908c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -3142,7 +3142,7 @@
             return;
         }
 
-        setHdmiCecVolumeControlEnabled(false);
+        mHdmiCecVolumeControlEnabled = false;
         // Call the vendor handler before the service is disabled.
         invokeVendorCommandListenersOnControlStateChanged(false,
                 HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING);
diff --git a/services/core/java/com/android/server/notification/NotificationChannelLogger.java b/services/core/java/com/android/server/notification/NotificationChannelLogger.java
index a7b1877..5c127c3 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelLogger.java
@@ -99,6 +99,16 @@
     }
 
     /**
+     * Log blocking or unblocking of the entire app's notifications.
+     * @param uid UID of the app.
+     * @param pkg Package name of the app.
+     * @param enabled If true, notifications are now allowed.
+     */
+    default void logAppNotificationsAllowed(int uid, String pkg, boolean enabled) {
+        logAppEvent(NotificationChannelEvent.getBlocked(enabled), uid, pkg);
+    }
+
+    /**
      * Low-level interface for logging events, to be implemented.
      * @param event Event to log.
      * @param channel Notification channel.
@@ -124,6 +134,13 @@
             boolean wasBlocked);
 
     /**
+     * Low-level interface for logging app-as-a-whole events, to be implemented.
+     * @param uid UID of app.
+     * @param pkg Package of app.
+     */
+    void logAppEvent(@NonNull NotificationChannelEvent event, int uid, String pkg);
+
+    /**
      * The UiEvent enums that this class can log.
      */
     enum NotificationChannelEvent implements UiEventLogger.UiEventEnum {
@@ -144,8 +161,11 @@
         @UiEvent(doc = "System created a new conversation (sub-channel in a notification channel)")
         NOTIFICATION_CHANNEL_CONVERSATION_CREATED(272),
         @UiEvent(doc = "System deleted a new conversation (sub-channel in a notification channel)")
-        NOTIFICATION_CHANNEL_CONVERSATION_DELETED(274);
-
+        NOTIFICATION_CHANNEL_CONVERSATION_DELETED(274),
+        @UiEvent(doc = "All notifications for the app were blocked.")
+        APP_NOTIFICATIONS_BLOCKED(557),
+        @UiEvent(doc = "Notifications for the app as a whole were unblocked.")
+        APP_NOTIFICATIONS_UNBLOCKED(558);
 
         private final int mId;
         NotificationChannelEvent(int id) {
@@ -178,6 +198,10 @@
                     ? NotificationChannelEvent.NOTIFICATION_CHANNEL_GROUP_CREATED
                     : NotificationChannelEvent.NOTIFICATION_CHANNEL_GROUP_DELETED;
         }
+
+        public static NotificationChannelEvent getBlocked(boolean enabled) {
+            return enabled ? APP_NOTIFICATIONS_UNBLOCKED : APP_NOTIFICATIONS_BLOCKED;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
index 2f7772e..fd3dd56 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
@@ -19,6 +19,8 @@
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.util.FrameworkStatsLog;
 
 /**
@@ -27,6 +29,8 @@
  * should live in the interface so it can be tested.
  */
 public class NotificationChannelLoggerImpl implements NotificationChannelLogger {
+    UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
+
     @Override
     public void logNotificationChannel(NotificationChannelEvent event,
             NotificationChannel channel, int uid, String pkg,
@@ -51,4 +55,9 @@
                 /* int old_importance*/ NotificationChannelLogger.getImportance(wasBlocked),
                 /* int importance*/ NotificationChannelLogger.getImportance(channelGroup));
     }
+
+    @Override
+    public void logAppEvent(NotificationChannelEvent event, int uid, String pkg) {
+        mUiEventLogger.log(event, uid, pkg);
+    }
 }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index e472e30..afc7557 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1654,6 +1654,7 @@
         }
         setImportance(packageName, uid,
                 enabled ? DEFAULT_IMPORTANCE : IMPORTANCE_NONE);
+        mNotificationChannelLogger.logAppNotificationsAllowed(uid, packageName, enabled);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 5b9db64..ccda587 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -19,6 +19,8 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -27,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
 import android.content.pm.parsing.component.ParsedComponent;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedIntentInfo;
@@ -108,12 +111,25 @@
     private final boolean mSystemAppsQueryable;
 
     private final FeatureConfig mFeatureConfig;
-
     private final OverlayReferenceMapper mOverlayReferenceMapper;
+    private final StateProvider mStateProvider;
+
     private PackageParser.SigningDetails mSystemSigningDetails;
     private Set<String> mProtectedBroadcasts = new ArraySet<>();
 
-    AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist,
+    /**
+     * This structure maps uid -> uid and indicates whether access from the first should be
+     * filtered to the second. It's essentially a cache of the
+     * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call.
+     * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on
+     * initial scam and is null until {@link #onSystemReady()} is called.
+     */
+    private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;
+
+    @VisibleForTesting(visibility = PRIVATE)
+    AppsFilter(StateProvider stateProvider,
+            FeatureConfig featureConfig,
+            String[] forceQueryableWhitelist,
             boolean systemAppsQueryable,
             @Nullable OverlayReferenceMapper.Provider overlayProvider) {
         mFeatureConfig = featureConfig;
@@ -121,8 +137,23 @@
         mSystemAppsQueryable = systemAppsQueryable;
         mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
                 overlayProvider);
+        mStateProvider = stateProvider;
     }
 
+    /**
+     * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding
+     * the data with the package lock.
+     */
+    @VisibleForTesting(visibility = PRIVATE)
+    public interface StateProvider {
+        void runWithState(CurrentStateCallback callback);
+
+        interface CurrentStateCallback {
+            void currentState(ArrayMap<String, PackageSetting> settings, UserInfo[] users);
+        }
+    }
+
+    @VisibleForTesting(visibility = PRIVATE)
     public interface FeatureConfig {
 
         /** Called when the system is ready and components can be queried. */
@@ -139,6 +170,7 @@
 
         /**
          * Turns on logging for the given appId
+         *
          * @param enable true if logging should be enabled, false if disabled.
          */
         void enableLogging(int appId, boolean enable);
@@ -146,6 +178,7 @@
         /**
          * Initializes the package enablement state for the given package. This gives opportunity
          * to do any expensive operations ahead of the actual checks.
+         *
          * @param removed true if adding, false if removing
          */
         void updatePackageState(PackageSetting setting, boolean removed);
@@ -161,6 +194,7 @@
 
         @Nullable
         private SparseBooleanArray mLoggingEnabled = null;
+        private AppsFilter mAppsFilter;
 
         private FeatureConfigImpl(
                 PackageManagerInternal pmInternal, PackageManagerService.Injector injector) {
@@ -168,6 +202,10 @@
             mInjector = injector;
         }
 
+        public void setAppsFilter(AppsFilter filter) {
+            mAppsFilter = filter;
+        }
+
         @Override
         public void onSystemReady() {
             mFeatureEnabled = DeviceConfig.getBoolean(
@@ -235,11 +273,12 @@
         @Override
         public void onCompatChange(String packageName) {
             updateEnabledState(mPmInternal.getPackage(packageName));
+            mAppsFilter.updateShouldFilterCacheForPackage(packageName);
         }
 
         private void updateEnabledState(AndroidPackage pkg) {
             // TODO(b/135203078): Do not use toAppInfo
-            final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternal(
+            final boolean enabled = mInjector.getCompatibility().isChangeEnabled(
                     PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
             if (enabled) {
                 mDisabledPackages.remove(pkg.getPackageName());
@@ -267,7 +306,7 @@
         final boolean forceSystemAppsQueryable =
                 injector.getContext().getResources()
                         .getBoolean(R.bool.config_forceSystemPackagesQueryable);
-        final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector);
+        final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector);
         final String[] forcedQueryablePackageNames;
         if (forceSystemAppsQueryable) {
             // all system apps already queryable, no need to read and parse individual exceptions
@@ -280,8 +319,16 @@
                 forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
             }
         }
-        return new AppsFilter(featureConfig, forcedQueryablePackageNames,
-                forceSystemAppsQueryable, null);
+        final StateProvider stateProvider = command -> {
+            synchronized (injector.getLock()) {
+                command.currentState(injector.getSettings().mPackages,
+                        injector.getUserManagerInternal().getUserInfos());
+            }
+        };
+        AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
+                forcedQueryablePackageNames, forceSystemAppsQueryable, null);
+        featureConfig.setAppsFilter(appsFilter);
+        return appsFilter;
     }
 
     public FeatureConfig getFeatureConfig() {
@@ -404,27 +451,59 @@
      * visibility of the caller from the target.
      *
      * @param recipientUid the uid gaining visibility of the {@code visibleUid}.
-     * @param visibleUid the uid becoming visible to the {@recipientUid}
+     * @param visibleUid   the uid becoming visible to the {@recipientUid}
      */
     public void grantImplicitAccess(int recipientUid, int visibleUid) {
-        if (recipientUid != visibleUid
-                && mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
-            Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+        if (recipientUid != visibleUid) {
+            if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
+                Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+            }
+            if (mShouldFilterCache != null) {
+                // update the cache in a one-off manner since we've got all the information we need.
+                SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid);
+                if (visibleUids == null) {
+                    visibleUids = new SparseBooleanArray();
+                    mShouldFilterCache.put(recipientUid, visibleUids);
+                }
+                visibleUids.put(visibleUid, false);
+            }
         }
     }
 
     public void onSystemReady() {
+        mStateProvider.runWithState(new StateProvider.CurrentStateCallback() {
+            @Override
+            public void currentState(ArrayMap<String, PackageSetting> settings,
+                    UserInfo[] users) {
+                mShouldFilterCache = new SparseArray<>(users.length * settings.size());
+            }
+        });
         mFeatureConfig.onSystemReady();
         mOverlayReferenceMapper.rebuildIfDeferred();
+        updateEntireShouldFilterCache();
     }
 
     /**
      * Adds a package that should be considered when filtering visibility between apps.
      *
-     * @param newPkgSetting    the new setting being added
-     * @param existingSettings all other settings currently on the device.
+     * @param newPkgSetting the new setting being added
      */
-    public void addPackage(PackageSetting newPkgSetting,
+    public void addPackage(PackageSetting newPkgSetting) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
+        try {
+            mStateProvider.runWithState((settings, users) -> {
+                addPackageInternal(newPkgSetting, settings);
+                if (mShouldFilterCache != null) {
+                    updateShouldFilterCacheForPackage(
+                            null, newPkgSetting, settings, users, settings.size());
+                } // else, rebuild entire cache when system is ready
+            });
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    private void addPackageInternal(PackageSetting newPkgSetting,
             ArrayMap<String, PackageSetting> existingSettings) {
         if (Objects.equals("android", newPkgSetting.name)) {
             // let's set aside the framework signatures
@@ -438,79 +517,153 @@
             }
         }
 
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
-        try {
-            final AndroidPackage newPkg = newPkgSetting.pkg;
-            if (newPkg == null) {
-                // nothing to add
-                return;
-            }
+        final AndroidPackage newPkg = newPkgSetting.pkg;
+        if (newPkg == null) {
+            // nothing to add
+            return;
+        }
 
-            if (!newPkg.getProtectedBroadcasts().isEmpty()) {
-                mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts());
-                recomputeComponentVisibility(existingSettings, newPkg.getPackageName());
-            }
+        if (!newPkg.getProtectedBroadcasts().isEmpty()) {
+            mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts());
+            recomputeComponentVisibility(existingSettings, newPkg.getPackageName());
+        }
 
-            final boolean newIsForceQueryable =
-                    mForceQueryable.contains(newPkgSetting.appId)
-                            /* shared user that is already force queryable */
-                            || newPkg.isForceQueryable()
-                            || newPkgSetting.forceQueryableOverride
-                            || (newPkgSetting.isSystem() && (mSystemAppsQueryable
-                            || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
-                            newPkg.getPackageName())));
-            if (newIsForceQueryable
-                    || (mSystemSigningDetails != null
-                            && isSystemSigned(mSystemSigningDetails, newPkgSetting))) {
-                mForceQueryable.add(newPkgSetting.appId);
-            }
+        final boolean newIsForceQueryable =
+                mForceQueryable.contains(newPkgSetting.appId)
+                        /* shared user that is already force queryable */
+                        || newPkg.isForceQueryable()
+                        || newPkgSetting.forceQueryableOverride
+                        || (newPkgSetting.isSystem() && (mSystemAppsQueryable
+                        || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
+                        newPkg.getPackageName())));
+        if (newIsForceQueryable
+                || (mSystemSigningDetails != null
+                && isSystemSigned(mSystemSigningDetails, newPkgSetting))) {
+            mForceQueryable.add(newPkgSetting.appId);
+        }
 
-            for (int i = existingSettings.size() - 1; i >= 0; i--) {
-                final PackageSetting existingSetting = existingSettings.valueAt(i);
-                if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) {
-                    continue;
+        for (int i = existingSettings.size() - 1; i >= 0; i--) {
+            final PackageSetting existingSetting = existingSettings.valueAt(i);
+            if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) {
+                continue;
+            }
+            final AndroidPackage existingPkg = existingSetting.pkg;
+            // let's evaluate the ability of already added packages to see this new package
+            if (!newIsForceQueryable) {
+                if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) {
+                    mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId);
                 }
-                final AndroidPackage existingPkg = existingSetting.pkg;
-                // let's evaluate the ability of already added packages to see this new package
-                if (!newIsForceQueryable) {
-                    if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) {
-                        mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId);
-                    }
-                    if (canQueryViaPackage(existingPkg, newPkg)
-                            || canQueryAsInstaller(existingSetting, newPkg)) {
-                        mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
-                    }
-                }
-                // now we'll evaluate our new package's ability to see existing packages
-                if (!mForceQueryable.contains(existingSetting.appId)) {
-                    if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) {
-                        mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId);
-                    }
-                    if (canQueryViaPackage(newPkg, existingPkg)
-                            || canQueryAsInstaller(newPkgSetting, existingPkg)) {
-                        mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
-                    }
-                }
-                // if either package instruments the other, mark both as visible to one another
-                if (pkgInstruments(newPkgSetting, existingSetting)
-                        || pkgInstruments(existingSetting, newPkgSetting)) {
-                    mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
+                if (canQueryViaPackage(existingPkg, newPkg)
+                        || canQueryAsInstaller(existingSetting, newPkg)) {
                     mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
                 }
             }
-
-            int existingSize = existingSettings.size();
-            ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize);
-            for (int index = 0; index < existingSize; index++) {
-                PackageSetting pkgSetting = existingSettings.valueAt(index);
-                if (pkgSetting.pkg != null) {
-                    existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
+            // now we'll evaluate our new package's ability to see existing packages
+            if (!mForceQueryable.contains(existingSetting.appId)) {
+                if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) {
+                    mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId);
+                }
+                if (canQueryViaPackage(newPkg, existingPkg)
+                        || canQueryAsInstaller(newPkgSetting, existingPkg)) {
+                    mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
                 }
             }
-            mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
-            mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            // if either package instruments the other, mark both as visible to one another
+            if (pkgInstruments(newPkgSetting, existingSetting)
+                    || pkgInstruments(existingSetting, newPkgSetting)) {
+                mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
+                mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
+            }
+        }
+
+        int existingSize = existingSettings.size();
+        ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize);
+        for (int index = 0; index < existingSize; index++) {
+            PackageSetting pkgSetting = existingSettings.valueAt(index);
+            if (pkgSetting.pkg != null) {
+                existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
+            }
+        }
+        mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
+        mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
+    }
+
+    private void removeAppIdFromVisibilityCache(int appId) {
+        if (mShouldFilterCache == null) {
+            return;
+        }
+        for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) {
+            if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) {
+                mShouldFilterCache.removeAt(i);
+                continue;
+            }
+            SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i);
+            for (int j = targetSparseArray.size() - 1; j >= 0; j--) {
+                if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) {
+                    targetSparseArray.removeAt(j);
+                }
+            }
+        }
+    }
+
+    private void updateEntireShouldFilterCache() {
+        mStateProvider.runWithState((settings, users) -> {
+            mShouldFilterCache.clear();
+            for (int i = settings.size() - 1; i >= 0; i--) {
+                updateShouldFilterCacheForPackage(
+                        null /*skipPackage*/, settings.valueAt(i), settings, users, i);
+            }
+        });
+    }
+
+    public void onUsersChanged() {
+        if (mShouldFilterCache != null) {
+            updateEntireShouldFilterCache();
+        }
+    }
+
+    private void updateShouldFilterCacheForPackage(String packageName) {
+        mStateProvider.runWithState((settings, users) -> {
+            updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName),
+                    settings, users, settings.size() /*maxIndex*/);
+        });
+
+    }
+
+    private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName,
+            PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings,
+            UserInfo[] allUsers, int maxIndex) {
+        for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) {
+            PackageSetting otherSetting = allSettings.valueAt(i);
+            if (subjectSetting.appId == otherSetting.appId) {
+                continue;
+            }
+            //noinspection StringEquality
+            if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) {
+                continue;
+            }
+            final int userCount = allUsers.length;
+            final int appxUidCount = userCount * allSettings.size();
+            for (int su = 0; su < userCount; su++) {
+                int subjectUser = allUsers[su].id;
+                for (int ou = su; ou < userCount; ou++) {
+                    int otherUser = allUsers[ou].id;
+                    int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
+                    if (!mShouldFilterCache.contains(subjectUid)) {
+                        mShouldFilterCache.put(subjectUid, new SparseBooleanArray(appxUidCount));
+                    }
+                    int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
+                    if (!mShouldFilterCache.contains(otherUid)) {
+                        mShouldFilterCache.put(otherUid, new SparseBooleanArray(appxUidCount));
+                    }
+                    mShouldFilterCache.get(subjectUid).put(otherUid,
+                            shouldFilterApplicationInternal(
+                                    subjectUid, subjectSetting, otherSetting, otherUser));
+                    mShouldFilterCache.get(otherUid).put(subjectUid,
+                            shouldFilterApplicationInternal(
+                                    otherUid, otherSetting, subjectSetting, subjectUser));
+                }
+            }
         }
     }
 
@@ -561,6 +714,7 @@
             }
         }
     }
+
     /**
      * Fetches all app Ids that a given setting is currently visible to, per provided user. This
      * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see
@@ -569,11 +723,11 @@
      * If the setting is visible to all UIDs, null is returned. If an app is not visible to any
      * applications, the int array will be empty.
      *
-     * @param users the set of users that should be evaluated for this calculation
+     * @param users            the set of users that should be evaluated for this calculation
      * @param existingSettings the set of all package settings that currently exist on device
      * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
-     *         provided setting or null if the app is visible to all and no whitelist should be
-     *         applied.
+     * provided setting or null if the app is visible to all and no whitelist should be
+     * applied.
      */
     @Nullable
     public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users,
@@ -618,52 +772,61 @@
     /**
      * Removes a package for consideration when filtering visibility between apps.
      *
-     * @param setting  the setting of the package being removed.
-     * @param allUsers array of all current users on device.
+     * @param setting the setting of the package being removed.
      */
-    public void removePackage(PackageSetting setting, int[] allUsers,
-            ArrayMap<String, PackageSetting> existingSettings) {
+    public void removePackage(PackageSetting setting) {
+        removeAppIdFromVisibilityCache(setting.appId);
+        mStateProvider.runWithState((settings, users) -> {
+            final int userCount = users.length;
+            for (int u = 0; u < userCount; u++) {
+                final int userId = users[u].id;
+                final int removingUid = UserHandle.getUid(userId, setting.appId);
+                mImplicitlyQueryable.remove(removingUid);
+                for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
+                    mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
+                }
+            }
+
+            mQueriesViaComponent.remove(setting.appId);
+            for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
+                mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId);
+            }
+            mQueriesViaPackage.remove(setting.appId);
+            for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
+                mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
+            }
+
+            // re-add other shared user members to re-establish visibility between them and other
+            // packages
+            if (setting.sharedUser != null) {
+                for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
+                    if (setting.sharedUser.packages.valueAt(i) == setting) {
+                        continue;
+                    }
+                    addPackageInternal(
+                            setting.sharedUser.packages.valueAt(i), settings);
+                }
+            }
+
+            if (!setting.pkg.getProtectedBroadcasts().isEmpty()) {
+                final String removingPackageName = setting.pkg.getPackageName();
+                mProtectedBroadcasts.clear();
+                mProtectedBroadcasts.addAll(
+                        collectProtectedBroadcasts(settings, removingPackageName));
+                recomputeComponentVisibility(settings, removingPackageName);
+            }
+
+            mOverlayReferenceMapper.removePkg(setting.name);
+            mFeatureConfig.updatePackageState(setting, true /*removed*/);
+
+            if (mShouldFilterCache != null) {
+                updateShouldFilterCacheForPackage(
+                        setting.name, setting, settings, users, settings.size());
+            }
+        });
         mForceQueryable.remove(setting.appId);
 
-        for (int u = 0; u < allUsers.length; u++) {
-            final int userId = allUsers[u];
-            final int removingUid = UserHandle.getUid(userId, setting.appId);
-            mImplicitlyQueryable.remove(removingUid);
-            for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
-                mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
-            }
-        }
 
-        mQueriesViaComponent.remove(setting.appId);
-        for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
-            mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId);
-        }
-        mQueriesViaPackage.remove(setting.appId);
-        for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
-            mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
-        }
-
-        // re-add other shared user members to re-establish visibility between them and other
-        // packages
-        if (setting.sharedUser != null) {
-            for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
-                if (setting.sharedUser.packages.valueAt(i) == setting) {
-                    continue;
-                }
-                addPackage(setting.sharedUser.packages.valueAt(i), existingSettings);
-            }
-        }
-
-        if (!setting.pkg.getProtectedBroadcasts().isEmpty()) {
-            final String removingPackageName = setting.pkg.getPackageName();
-            mProtectedBroadcasts.clear();
-            mProtectedBroadcasts.addAll(
-                    collectProtectedBroadcasts(existingSettings, removingPackageName));
-            recomputeComponentVisibility(existingSettings, removingPackageName);
-        }
-
-        mOverlayReferenceMapper.removePkg(setting.name);
-        mFeatureConfig.updatePackageState(setting, true /*removed*/);
     }
 
     /**
@@ -680,11 +843,32 @@
             PackageSetting targetPkgSetting, int userId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
         try {
-
-            if (!shouldFilterApplicationInternal(
-                    callingUid, callingSetting, targetPkgSetting, userId)) {
+            if (callingUid < Process.FIRST_APPLICATION_UID
+                    || UserHandle.getAppId(callingUid) == targetPkgSetting.appId) {
                 return false;
             }
+            if (mShouldFilterCache != null) { // use cache
+                SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid);
+                final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId);
+                if (shouldFilterTargets == null) {
+                    Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid);
+                    return true;
+                }
+                int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid);
+                if (indexOfTargetUid < 0) {
+                    Slog.w(TAG, "Encountered calling -> target with no cached rules: "
+                            + callingUid + " -> " + targetUid);
+                    return true;
+                }
+                if (!shouldFilterTargets.valueAt(indexOfTargetUid)) {
+                    return false;
+                }
+            } else {
+                if (!shouldFilterApplicationInternal(
+                        callingUid, callingSetting, targetPkgSetting, userId)) {
+                    return false;
+                }
+            }
             if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) {
                 log(callingSetting, targetPkgSetting, "BLOCKED");
             }
@@ -695,7 +879,7 @@
     }
 
     private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting,
-            PackageSetting targetPkgSetting, int userId) {
+            PackageSetting targetPkgSetting, int targetUserId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal");
         try {
             final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
@@ -705,12 +889,6 @@
                 }
                 return false;
             }
-            if (callingUid < Process.FIRST_APPLICATION_UID) {
-                if (DEBUG_LOGGING) {
-                    Slog.d(TAG, "filtering skipped; " + callingUid + " is system");
-                }
-                return false;
-            }
             if (callingSetting == null) {
                 Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
                 return true;
@@ -719,8 +897,14 @@
             final ArraySet<PackageSetting> callingSharedPkgSettings;
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof");
             if (callingSetting instanceof PackageSetting) {
-                callingPkgSetting = (PackageSetting) callingSetting;
-                callingSharedPkgSettings = null;
+                if (((PackageSetting) callingSetting).sharedUser == null) {
+                    callingPkgSetting = (PackageSetting) callingSetting;
+                    callingSharedPkgSettings = null;
+                } else {
+                    callingPkgSetting = null;
+                    callingSharedPkgSettings =
+                            ((PackageSetting) callingSetting).sharedUser.packages;
+                }
             } else {
                 callingPkgSetting = null;
                 callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages;
@@ -778,13 +962,19 @@
             }
 
             try {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission");
-                if (callingSetting.getPermissionsState().hasPermission(
-                        Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) {
-                    if (DEBUG_LOGGING) {
-                        log(callingSetting, targetPkgSetting, "has query-all permission");
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages");
+                if (callingPkgSetting != null) {
+                        if (callingPkgSetting.pkg != null
+                                && requestsQueryAllPackages(callingPkgSetting.pkg)) {
+                            return false;
+                        }
+                } else {
+                    for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
+                        AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).pkg;
+                        if (pkg != null && requestsQueryAllPackages(pkg)) {
+                            return false;
+                        }
                     }
-                    return false;
                 }
             } finally {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -825,7 +1015,7 @@
 
             try {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
-                final int targetUid = UserHandle.getUid(userId, targetAppId);
+                final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
                 if (mImplicitlyQueryable.contains(callingUid, targetUid)) {
                     if (DEBUG_LOGGING) {
                         log(callingSetting, targetPkgSetting, "implicitly queryable for user");
@@ -863,13 +1053,20 @@
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
 
-
             return true;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
+
+    private static boolean requestsQueryAllPackages(@NonNull AndroidPackage pkg) {
+        // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the
+        // package directly
+        return pkg.getRequestedPermissions().contains(
+                Manifest.permission.QUERY_ALL_PACKAGES);
+    }
+
     /** Returns {@code true} if the source package instruments the target package. */
     private static boolean pkgInstruments(PackageSetting source, PackageSetting target) {
         try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ae8b3a0..f3bc056 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12362,7 +12362,7 @@
             ksms.addScannedPackageLPw(pkg);
 
             mComponentResolver.addAllComponents(pkg, chatty);
-            mAppsFilter.addPackage(pkgSetting, mSettings.mPackages);
+            mAppsFilter.addPackage(pkgSetting);
 
             // Don't allow ephemeral applications to define new permissions groups.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
@@ -12536,8 +12536,6 @@
 
     void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
         mComponentResolver.removeAllComponents(pkg, chatty);
-        mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()),
-                mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages);
         mPermissionManager.removeAllPermissions(pkg, chatty);
 
         final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
@@ -14264,7 +14262,7 @@
             // Okay!
             targetPackageSetting.setInstallerPackageName(installerPackageName);
             mSettings.addInstallerPackageNames(targetPackageSetting.installSource);
-            mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages);
+            mAppsFilter.addPackage(targetPackageSetting);
             scheduleWriteSettingsLocked();
         }
     }
@@ -18717,6 +18715,7 @@
                     clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
                     clearDefaultBrowserIfNeeded(packageName);
                     mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
+                    mAppsFilter.removePackage(getPackageSetting(packageName));
                     removedAppId = mSettings.removePackageLPw(packageName);
                     if (outInfo != null) {
                         outInfo.removedAppId = removedAppId;
@@ -23474,6 +23473,7 @@
             scheduleWritePackageRestrictionsLocked(userId);
             scheduleWritePackageListLocked(userId);
             primeDomainVerificationsLPw(userId);
+            mAppsFilter.onUsersChanged();
         }
     }
 
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 d3f3ba1..1b11e2d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2509,6 +2509,9 @@
 
                 for (String permissionName : requestedPermissions) {
                     BasePermission permission = mSettings.getPermission(permissionName);
+                    if (permission == null) {
+                        continue;
+                    }
                     if (Objects.equals(permission.getSourcePackageName(), PLATFORM_PACKAGE_NAME)
                             && permission.isRuntime() && !permission.isRemoved()) {
                         if (permission.isHardOrSoftRestricted()
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5668454..304860c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6456,14 +6456,15 @@
 
     @Override
     public boolean matchParentBounds() {
-        if (super.matchParentBounds() && mCompatDisplayInsets == null) {
+        final Rect overrideBounds = getResolvedOverrideBounds();
+        if (overrideBounds.isEmpty()) {
             return true;
         }
-        // An activity in size compatibility mode may have resolved override bounds, so the exact
-        // bounds should also be checked. Otherwise IME window will show with offset. See
-        // {@link DisplayContent#isImeAttachedToApp}.
+        // An activity in size compatibility mode may have override bounds which equals to its
+        // parent bounds, so the exact bounds should also be checked to allow IME window to attach
+        // to the activity. See {@link DisplayContent#isImeAttachedToApp}.
         final WindowContainer parent = getParent();
-        return parent == null || parent.getBounds().equals(getResolvedOverrideBounds());
+        return parent == null || parent.getBounds().equals(overrideBounds);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d558839..c24c1e4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -32,6 +32,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.os.Build.VERSION_CODES.N;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
@@ -1526,12 +1527,12 @@
     }
 
     /**
-     * Sets the provided record to {@link mFixedRotationLaunchingApp} if possible to apply fixed
+     * Sets the provided record to {@link #mFixedRotationLaunchingApp} if possible to apply fixed
      * rotation transform to it and indicate that the display may be rotated after it is launched.
      */
     void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Surface.Rotation int rotation) {
         final WindowToken prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
-        if (prevRotatedLaunchingApp != null && prevRotatedLaunchingApp == r
+        if (prevRotatedLaunchingApp == r
                 && r.getWindowConfiguration().getRotation() == rotation) {
             // The given launching app and target rotation are the same as the existing ones.
             return;
@@ -5659,6 +5660,16 @@
             }
         }
 
+        /**
+         * Return {@code true} if there is an ongoing animation to the "Recents" activity and this
+         * activity as a fixed orientation so shouldn't be rotated.
+         */
+        boolean isFixedOrientationRecentsAnimating() {
+            return mAnimatingRecents != null
+                    && mAnimatingRecents.getRequestedConfigurationOrientation()
+                    != ORIENTATION_UNDEFINED;
+        }
+
         @Override
         public void onAppTransitionFinishedLocked(IBinder token) {
             final ActivityRecord r = getActivityRecord(token);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 831491d..f093fd3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -430,6 +430,15 @@
                         "Deferring rotation, still finishing previous rotation");
                 return false;
             }
+
+            if (mDisplayContent.mFixedRotationTransitionListener
+                    .isFixedOrientationRecentsAnimating()) {
+                // During the recents animation, the closing app might still be considered on top.
+                // In order to ignore its requested orientation to avoid a sensor led rotation (e.g
+                // user rotating the device while the recents animation is running), we ignore
+                // rotation update while the animation is running.
+                return false;
+            }
         }
 
         if (!mService.mDisplayEnabled) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c749125..6670dbf 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2927,9 +2927,17 @@
         // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen
         // they extend past their stack and sysui uses the stack surface to control cropping.
         // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
-        final boolean isTopHomeOrRecents = (isActivityTypeHome() || isActivityTypeRecents())
-                && getRootTask().getTopMostTask() == this;
-        return isResizeable() && !isTopHomeOrRecents;
+        if (isActivityTypeHome() || isActivityTypeRecents()) {
+            // Make sure this is the top-most non-organizer root task (if not top-most, it means
+            // another translucent task could be above this, so this needs to stay cropped.
+            final Task rootTask = getRootTask();
+            final Task topNonOrgTask =
+                    rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask;
+            if (isDescendantOf(topNonOrgTask)) {
+                return false;
+            }
+        }
+        return isResizeable();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 1a2672b..51cf858 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.RecordingCanvas;
@@ -37,8 +38,11 @@
 import android.os.Handler;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.view.InsetsSource;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.ThreadedRenderer;
+import android.view.WindowInsets;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -475,9 +479,12 @@
         final int color = ColorUtils.setAlphaComponent(
                 task.getTaskDescription().getBackgroundColor(), 255);
         final LayoutParams attrs = mainWindow.getAttrs();
+        final InsetsPolicy insetsPolicy = mainWindow.getDisplayContent().getInsetsPolicy();
+        final InsetsState insetsState = insetsPolicy.getInsetsForDispatch(mainWindow);
+        final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrameLw(), insetsState);
         final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
                 attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
-                mHighResTaskSnapshotScale, mainWindow.getRequestedInsetsState());
+                mHighResTaskSnapshotScale, insetsState);
         final int taskWidth = task.getBounds().width();
         final int taskHeight = task.getBounds().height();
         final int width = (int) (taskWidth * mHighResTaskSnapshotScale);
@@ -488,7 +495,7 @@
         node.setClipToBounds(false);
         final RecordingCanvas c = node.start(width, height);
         c.drawColor(color);
-        decorPainter.setInsets(mainWindow.getContentInsets(), mainWindow.getStableInsets());
+        decorPainter.setInsets(systemBarInsets);
         decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
         node.end(c);
         final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
@@ -593,6 +600,13 @@
         return 0;
     }
 
+    static Rect getSystemBarInsets(Rect frame, InsetsState state) {
+        return state.calculateInsets(frame, null /* ignoringVisibilityState */,
+                false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
+                null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacySystemUiFlags */,
+                null /* typeSideMap */).getInsets(WindowInsets.Type.systemBars()).toRect();
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "mHighResTaskSnapshotScale=" + mHighResTaskSnapshotScale);
         mCache.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index e26f1e1..f1f5762 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -39,10 +39,9 @@
 
 import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
 import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.getColorViewLeftInset;
-import static com.android.internal.policy.DecorView.getColorViewTopInset;
 import static com.android.internal.policy.DecorView.getNavigationBarRect;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.TaskSnapshotController.getSystemBarInsets;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -131,9 +130,8 @@
     private final IWindowSession mSession;
     private final WindowManagerService mService;
     private final Rect mTaskBounds;
-    private final Rect mStableInsets = new Rect();
-    private final Rect mContentInsets = new Rect();
     private final Rect mFrame = new Rect();
+    private final Rect mSystemBarInsets = new Rect();
     private TaskSnapshot mSnapshot;
     private final RectF mTmpSnapshotSize = new RectF();
     private final RectF mTmpDstFrame = new RectF();
@@ -174,6 +172,7 @@
         final int windowFlags;
         final int windowPrivateFlags;
         final int currentOrientation;
+        final InsetsState insetsState;
         synchronized (service.mGlobalLock) {
             final WindowState mainWindow = activity.findMainWindow();
             final Task task = activity.getTask();
@@ -241,6 +240,10 @@
             taskBounds = new Rect();
             task.getBounds(taskBounds);
             currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation;
+
+            final InsetsPolicy insetsPolicy = topFullscreenOpaqueWindow.getDisplayContent()
+                    .getInsetsPolicy();
+            insetsState = insetsPolicy.getInsetsForDispatch(topFullscreenOpaqueWindow);
         }
         try {
             final int res = session.addToDisplay(window, window.mSeq, layoutParams,
@@ -255,8 +258,7 @@
         }
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                 surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
-                windowFlags, windowPrivateFlags, taskBounds,
-                currentOrientation, topFullscreenOpaqueWindow.getRequestedInsetsState());
+                windowFlags, windowPrivateFlags, taskBounds, currentOrientation, insetsState);
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
@@ -266,7 +268,9 @@
         } catch (RemoteException e) {
             // Local call.
         }
-        snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
+
+        final Rect systemBarInsets = getSystemBarInsets(tmpFrame, insetsState);
+        snapshotSurface.setFrames(tmpFrame, systemBarInsets);
         snapshotSurface.drawSnapshot();
         return snapshotSurface;
     }
@@ -315,13 +319,12 @@
     }
 
     @VisibleForTesting
-    void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
+    void setFrames(Rect frame, Rect systemBarInsets) {
         mFrame.set(frame);
-        mContentInsets.set(contentInsets);
-        mStableInsets.set(stableInsets);
+        mSystemBarInsets.set(systemBarInsets);
         mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
                 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
-        mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
+        mSystemBarBackgroundPainter.setInsets(systemBarInsets);
     }
 
     private void drawSnapshot() {
@@ -453,9 +456,7 @@
         );
 
         // However, we also need to make space for the navigation bar on the left side.
-        final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
-                mContentInsets.left);
-        frame.offset(colorViewLeftInset, 0);
+        frame.offset(mSystemBarInsets.left, 0);
         return frame;
     }
 
@@ -540,8 +541,6 @@
      */
     static class SystemBarBackgroundPainter {
 
-        private final Rect mContentInsets = new Rect();
-        private final Rect mStableInsets = new Rect();
         private final Paint mStatusBarPaint = new Paint();
         private final Paint mNavigationBarPaint = new Paint();
         private final int mStatusBarColor;
@@ -551,6 +550,7 @@
         private final int mSysUiVis;
         private final float mScale;
         private final InsetsState mInsetsState;
+        private final Rect mSystemBarInsets = new Rect();
 
         SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int sysUiVis,
                 TaskDescription taskDescription, float scale, InsetsState insetsState) {
@@ -576,9 +576,8 @@
             mInsetsState = insetsState;
         }
 
-        void setInsets(Rect contentInsets, Rect stableInsets) {
-            mContentInsets.set(contentInsets);
-            mStableInsets.set(stableInsets);
+        void setInsets(Rect systemBarInsets) {
+            mSystemBarInsets.set(systemBarInsets);
         }
 
         int getStatusBarColorViewHeight() {
@@ -589,7 +588,7 @@
                             mSysUiVis, mStatusBarColor, mWindowFlags, forceBarBackground)
                     : STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
                             mInsetsState, mStatusBarColor, mWindowFlags, forceBarBackground)) {
-                return (int) (getColorViewTopInset(mStableInsets.top, mContentInsets.top) * mScale);
+                return (int) (mSystemBarInsets.top * mScale);
             } else {
                 return 0;
             }
@@ -615,8 +614,7 @@
                 int statusBarHeight) {
             if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
                     && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
-                final int rightInset = (int) (DecorView.getColorViewRightInset(mStableInsets.right,
-                        mContentInsets.right) * mScale);
+                final int rightInset = (int) (mSystemBarInsets.right * mScale);
                 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
                 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
             }
@@ -625,8 +623,8 @@
         @VisibleForTesting
         void drawNavigationBarBackground(Canvas c) {
             final Rect navigationBarRect = new Rect();
-            getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
-                    navigationBarRect, mScale);
+            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
+                    mScale);
             final boolean visible = isNavigationBarColorViewVisible();
             if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
                 c.drawRect(navigationBarRect, mNavigationBarPaint);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6406f0ae..dd08f42 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1032,7 +1032,8 @@
      * @return Whether this child is on top of the window hierarchy.
      */
     boolean isOnTop() {
-        return getParent().getTopChild() == this && getParent().isOnTop();
+        final WindowContainer parent = getParent();
+        return parent != null && parent.getTopChild() == this && parent.isOnTop();
     }
 
     /** Returns the top child container. */
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3532edf..5fc519c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2339,6 +2339,10 @@
             return false;
         }
 
+        if (inPinnedWindowingMode()) {
+            return false;
+        }
+
         final boolean windowsAreFocusable = mActivityRecord == null || mActivityRecord.windowsAreFocusable();
         if (!windowsAreFocusable) {
             // This window can't be an IME target if the app's windows should not be focusable.
@@ -3412,6 +3416,7 @@
     private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
         final Task task = getTask();
         if (task == null || !task.cropWindowsToStackBounds()) {
+            handle.setTouchableRegionCrop(null);
             return;
         }
 
@@ -5158,17 +5163,18 @@
         float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
         float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
         float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
-        int x = mSurfacePosition.x;
-        int y = mSurfacePosition.y;
+        transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
+        int x = mSurfacePosition.x + mTmpPoint.x;
+        int y = mSurfacePosition.y + mTmpPoint.y;
 
         // We might be on a display which has been re-parented to a view in another window, so here
         // computes the global location of our display.
         DisplayContent dc = getDisplayContent();
         while (dc != null && dc.getParentWindow() != null) {
             final WindowState displayParent = dc.getParentWindow();
-            x += displayParent.mWindowFrames.mFrame.left - displayParent.mAttrs.surfaceInsets.left
+            x += displayParent.mWindowFrames.mFrame.left
                     + (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f);
-            y += displayParent.mWindowFrames.mFrame.top - displayParent.mAttrs.surfaceInsets.top
+            y += displayParent.mWindowFrames.mFrame.top
                     + (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f);
             dc = displayParent.getDisplayContent();
         }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index c34b8e1..ac44cce 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -264,6 +264,19 @@
     }
 
     @Test
+    public void disableAndReenableCec_volumeControlReturnsToOriginalValue() {
+        boolean volumeControlEnabled = true;
+        mHdmiControlService.setHdmiCecVolumeControlEnabled(volumeControlEnabled);
+
+        mHdmiControlService.setControlEnabled(false);
+        assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isFalse();
+
+        mHdmiControlService.setControlEnabled(true);
+        assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isEqualTo(
+                volumeControlEnabled);
+    }
+
+    @Test
     public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled() {
         mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f205fde..4f21ee1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -32,6 +33,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.UserInfo;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -39,9 +41,11 @@
 import android.content.pm.parsing.component.ParsedProvider;
 import android.os.Build;
 import android.os.Process;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
 
@@ -57,26 +61,36 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
 
 import java.security.cert.CertificateException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.IntFunction;
+import java.util.stream.Collectors;
 
 @Presubmit
 @RunWith(JUnit4.class)
 public class AppsFilterTest {
 
-    private static final int DUMMY_CALLING_UID = 10345;
-    private static final int DUMMY_TARGET_UID = 10556;
-    private static final int DUMMY_ACTOR_UID = 10656;
-    private static final int DUMMY_OVERLAY_UID = 10756;
-    private static final int DUMMY_ACTOR_TWO_UID = 10856;
+    private static final int DUMMY_CALLING_APPID = 10345;
+    private static final int DUMMY_TARGET_APPID = 10556;
+    private static final int DUMMY_ACTOR_APPID = 10656;
+    private static final int DUMMY_OVERLAY_APPID = 10756;
+    private static final int SYSTEM_USER = 0;
+    private static final int SECONDARY_USER = 10;
+    private static final int[] USER_ARRAY = {SYSTEM_USER, SECONDARY_USER};
+    private static final UserInfo[] USER_INFO_LIST = Arrays.stream(USER_ARRAY).mapToObj(
+            id -> new UserInfo(id, Integer.toString(id), 0)).toArray(UserInfo[]::new);
 
     @Mock
     AppsFilter.FeatureConfig mFeatureConfigMock;
+    @Mock
+    AppsFilter.StateProvider mStateProvider;
 
     private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
 
@@ -170,15 +184,24 @@
         mExisting = new ArrayMap<>();
 
         MockitoAnnotations.initMocks(this);
+        doAnswer(invocation -> {
+            ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
+                    .currentState(mExisting, USER_INFO_LIST);
+            return null;
+        }).when(mStateProvider)
+                .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
+
         when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
-        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
-                .thenReturn(true);
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer(
+                (Answer<Boolean>) invocation ->
+                        ((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
+                                >= Build.VERSION_CODES.R);
     }
 
     @Test
     public void testSystemReadyPropogates() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         appsFilter.onSystemReady();
         verify(mFeatureConfigMock).onSystemReady();
     }
@@ -186,22 +209,23 @@
     @Test
     public void testQueriesAction_FilterMatches() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID);
+                pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         final Signature frameworkSignature = Mockito.mock(Signature.class);
         final PackageParser.SigningDetails frameworkSigningDetails =
                 new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
@@ -211,164 +235,174 @@
                 b -> b.setSigningDetails(frameworkSigningDetails));
         appsFilter.onSystemReady();
 
-        final int activityUid = DUMMY_TARGET_UID;
+        final int activityUid = DUMMY_TARGET_APPID;
         PackageSetting targetActivity = simulateAddPackage(appsFilter,
                 pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid);
-        final int receiverUid = DUMMY_TARGET_UID + 1;
+        final int receiverUid = DUMMY_TARGET_APPID + 1;
         PackageSetting targetReceiver = simulateAddPackage(appsFilter,
                 pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")),
                 receiverUid);
-        final int callingUid = DUMMY_CALLING_UID;
+        final int callingUid = DUMMY_CALLING_APPID;
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid);
-        final int wildcardUid = DUMMY_CALLING_UID + 1;
+        final int wildcardUid = DUMMY_CALLING_APPID + 1;
         PackageSetting callingWildCard = simulateAddPackage(appsFilter,
                 pkg("com.calling.wildcard", new Intent("*")), wildcardUid);
 
-        assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, 0));
-        assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, 0));
+        assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity,
+                SYSTEM_USER));
+        assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver,
+                SYSTEM_USER));
 
         assertFalse(appsFilter.shouldFilterApplication(
-                wildcardUid, callingWildCard, targetActivity, 0));
+                wildcardUid, callingWildCard, targetActivity, SYSTEM_USER));
         assertTrue(appsFilter.shouldFilterApplication(
-                wildcardUid, callingWildCard, targetReceiver, 0));
+                wildcardUid, callingWildCard, targetReceiver, SYSTEM_USER));
     }
 
     @Test
     public void testQueriesProvider_FilterMatches() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID);
+                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.authority"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesDifferentProvider_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID);
+                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.other.authority"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkgWithProvider("com.some.package", "com.some.authority;com.some.other.authority"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.authority"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesAction_NoMatchingAction_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
-        PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package",
-                        new Intent("TEST_ACTION"))
-                        .setTargetSdkVersion(Build.VERSION_CODES.P),
-                DUMMY_CALLING_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
+        ParsingPackage callingPkg = pkg("com.some.other.package",
+                new Intent("TEST_ACTION"))
+                .setTargetSdkVersion(Build.VERSION_CODES.P);
+        PackageSetting calling = simulateAddPackage(appsFilter, callingPkg,
+                DUMMY_CALLING_APPID);
 
-        when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testNoQueries_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testForceQueryable_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID);
+                pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
+                        false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID,
+                pkg("com.some.package"), DUMMY_TARGET_APPID,
                 setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
 
     @Test
     public void testSystemSignedTarget_DoesntFilter() throws CertificateException {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         appsFilter.onSystemReady();
 
         final Signature frameworkSignature = Mockito.mock(Signature.class);
@@ -382,62 +416,67 @@
         simulateAddPackage(appsFilter, pkg("android"), 1000,
                 b -> b.setSigningDetails(frameworkSigningDetails));
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID,
+                DUMMY_TARGET_APPID,
                 b -> b.setSigningDetails(frameworkSigningDetails)
                         .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID,
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID,
                 b -> b.setSigningDetails(otherSigningDetails));
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
+                        false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
 
     @Test
     public void testSystemQueryable_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{},
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{},
                         true /* system force queryable */, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID,
+                pkg("com.some.package"), DUMMY_TARGET_APPID,
                 setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesPackage_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
@@ -445,63 +484,67 @@
         when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(false);
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(
-                appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID);
+                appsFilter, pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(
-                appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testSystemUid_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(SYSTEM_USER, null, target, SYSTEM_USER));
         assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1,
-                null, target, 0));
+                null, target, SYSTEM_USER));
     }
 
     @Test
     public void testNonSystemUid_NoCallingSetting_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, null, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testNoTargetPackage_filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = new PackageSettingBuilder()
+                .setAppId(DUMMY_TARGET_APPID)
                 .setName("com.some.package")
                 .setCodePath("/")
                 .setResourcePath("/")
                 .setPVersionCode(1L)
                 .build();
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
@@ -516,7 +559,11 @@
                 .setOverlayTargetName("overlayableName");
         ParsingPackage actor = pkg("com.some.package.actor");
 
-        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+        final AppsFilter appsFilter = new AppsFilter(
+                mStateProvider,
+                mFeatureConfigMock,
+                new String[]{},
+                false,
                 new OverlayReferenceMapper.Provider() {
                     @Nullable
                     @Override
@@ -544,31 +591,34 @@
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
-        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
-        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
-        PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID);
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
+        PackageSetting overlaySetting =
+                simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID);
+        PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_APPID);
 
         // Actor can see both target and overlay
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
-                targetSetting, 0));
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
-                overlaySetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
+                targetSetting, SYSTEM_USER));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
+                overlaySetting, SYSTEM_USER));
 
         // But target/overlay can't see each other
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
-                overlaySetting, 0));
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
-                targetSetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting,
+                overlaySetting, SYSTEM_USER));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
+                targetSetting, SYSTEM_USER));
 
         // And can't see the actor
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
-                actorSetting, 0));
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
-                actorSetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting,
+                actorSetting, SYSTEM_USER));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
+                actorSetting, SYSTEM_USER));
     }
 
     @Test
     public void testActsOnTargetOfOverlayThroughSharedUser() throws Exception {
+//        Debug.waitForDebugger();
+
         final String actorName = "overlay://test/actorName";
 
         ParsingPackage target = pkg("com.some.package.target")
@@ -580,7 +630,11 @@
         ParsingPackage actorOne = pkg("com.some.package.actor.one");
         ParsingPackage actorTwo = pkg("com.some.package.actor.two");
 
-        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+        final AppsFilter appsFilter = new AppsFilter(
+                mStateProvider,
+                mFeatureConfigMock,
+                new String[]{},
+                false,
                 new OverlayReferenceMapper.Provider() {
                     @Nullable
                     @Override
@@ -609,108 +663,114 @@
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
-        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
-        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
-        PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID);
-        PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo,
-                DUMMY_ACTOR_TWO_UID);
-
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
         SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser",
-                actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags);
-        actorSharedSetting.addPackage(actorOneSetting);
-        actorSharedSetting.addPackage(actorTwoSetting);
+                targetSetting.pkgFlags, targetSetting.pkgPrivateFlags);
+        PackageSetting overlaySetting =
+                simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID);
+        simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_APPID,
+                null /*settingBuilder*/, actorSharedSetting);
+        simulateAddPackage(appsFilter, actorTwo, DUMMY_ACTOR_APPID,
+                null /*settingBuilder*/, actorSharedSetting);
+
 
         // actorTwo can see both target and overlay
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
-                targetSetting, 0));
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
-                overlaySetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting,
+                targetSetting, SYSTEM_USER));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting,
+                overlaySetting, SYSTEM_USER));
     }
 
     @Test
     public void testInitiatingApp_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(target.name, null, null, false));
+                DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, false));
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testUninstalledInitiatingApp_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(target.name, null, null, true));
+                DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, true));
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testOriginatingApp_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(null, target.name, null, false));
+                DUMMY_CALLING_APPID, withInstallSource(null, target.name, null, false));
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testInstallingApp_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(null, null, target.name, false));
+                DUMMY_CALLING_APPID, withInstallSource(null, null, target.name, false));
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testInstrumentation_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting instrumentation = simulateAddPackage(appsFilter,
                 pkgWithInstrumentation("com.some.other.package", "com.some.package"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
         assertFalse(
-                appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, instrumentation, target, 0));
+                appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+                        SYSTEM_USER));
         assertFalse(
-                appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, target, instrumentation, 0));
+                appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
+                        SYSTEM_USER));
     }
 
     @Test
     public void testWhoCanSee() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
@@ -718,6 +778,7 @@
         final int seesNothingAppId = Process.FIRST_APPLICATION_UID;
         final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
         final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
+
         PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
         PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
                 seesNothingAppId);
@@ -727,23 +788,25 @@
                 pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
                 queriesProviderAppId);
 
-        final int[] systemFilter =
-                appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0);
-        assertThat(toList(systemFilter), empty());
+        final SparseArray<int[]> systemFilter =
+                appsFilter.getVisibilityWhitelist(system, USER_ARRAY, mExisting);
+        assertThat(toList(systemFilter.get(SYSTEM_USER)), empty());
 
-        final int[] seesNothingFilter =
-                appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0);
-        assertThat(toList(seesNothingFilter),
+        final SparseArray<int[]> seesNothingFilter =
+                appsFilter.getVisibilityWhitelist(seesNothing, USER_ARRAY, mExisting);
+        assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
+                contains(seesNothingAppId));
+        assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
                 contains(seesNothingAppId));
 
-        final int[] hasProviderFilter =
-                appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0);
-        assertThat(toList(hasProviderFilter),
+        final SparseArray<int[]> hasProviderFilter =
+                appsFilter.getVisibilityWhitelist(hasProvider, USER_ARRAY, mExisting);
+        assertThat(toList(hasProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
 
-        int[] queriesProviderFilter =
-                appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0);
-        assertThat(toList(queriesProviderFilter),
+        SparseArray<int[]> queriesProviderFilter =
+                appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+        assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(queriesProviderAppId));
 
         // provider read
@@ -751,8 +814,8 @@
 
         // ensure implicit access is included in the filter
         queriesProviderFilter =
-                appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0);
-        assertThat(toList(queriesProviderFilter),
+                appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+        assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
     }
 
@@ -779,11 +842,17 @@
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
             ParsingPackage newPkgBuilder, int appId) {
-        return simulateAddPackage(filter, newPkgBuilder, appId, null);
+        return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/);
     }
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
             ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
+        return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/);
+    }
+
+    private PackageSetting simulateAddPackage(AppsFilter filter,
+                ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action,
+            @Nullable SharedUserSetting sharedUserSetting) {
         AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal();
 
         final PackageSettingBuilder settingBuilder = new PackageSettingBuilder()
@@ -795,8 +864,12 @@
                 .setPVersionCode(1L);
         final PackageSetting setting =
                 (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
-        filter.addPackage(setting, mExisting);
         mExisting.put(newPkg.getPackageName(), setting);
+        if (sharedUserSetting != null) {
+            sharedUserSetting.addPackage(setting);
+            setting.sharedUser = sharedUserSetting;
+        }
+        filter.addPackage(setting);
         return setting;
     }
 
@@ -809,4 +882,3 @@
         return setting -> setting.setInstallSource(installSource);
     }
 }
-
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
index b6ea063..f609306 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
@@ -51,4 +51,9 @@
             NotificationChannelGroup channelGroup, int uid, String pkg, boolean wasBlocked) {
         mCalls.add(new CallRecord(event));
     }
+
+    @Override
+    public void logAppEvent(NotificationChannelEvent event, int uid, String pkg) {
+        mCalls.add(new CallRecord(event));
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 622a203..2e49929 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2266,6 +2266,14 @@
     }
 
     @Test
+    public void testAppBlockedLogging() {
+        mHelper.setEnabled(PKG_N_MR1, 1020, false);
+        assertEquals(1, mLogger.getCalls().size());
+        assertEquals(
+                NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
+                mLogger.get(0).event);
+    }
+    @Test
     public void testXml_statusBarIcons_default() throws Exception {
         String preQXml = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 5a952b3..8cf8507 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -79,6 +80,7 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
 
 import android.annotation.SuppressLint;
 import android.app.ActivityTaskManager;
@@ -1231,11 +1233,29 @@
     }
 
     @Test
+    public void testRecentsNotRotatingWithFixedRotation() {
+        final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+        doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean());
+        doCallRealMethod().when(displayRotation).updateOrientation(anyInt(), anyBoolean());
+
+        final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS);
+        recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+        mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
+        displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
+        assertFalse(displayRotation.updateRotationUnchecked(false));
+
+        mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false);
+        assertTrue(displayRotation.updateRotationUnchecked(false));
+    }
+
+    @Test
     public void testRemoteRotation() {
         DisplayContent dc = createNewDisplay();
 
         final DisplayRotation dr = dc.getDisplayRotation();
-        Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
+        doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
         Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt());
         final boolean[] continued = new boolean[1];
         // TODO(display-merge): Remove cast
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 15b395c..e742b32 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -251,6 +251,13 @@
         mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity);
         // Make sure IME cannot attach to the app, otherwise IME window will also be shifted.
         assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
+
+        // Recompute the natural configuration without resolving size compat configuration.
+        mActivity.clearSizeCompatMode();
+        mActivity.onConfigurationChanged(mTask.getConfiguration());
+        // It should keep non-attachable because the resolved bounds will be computed according to
+        // the aspect ratio that won't match its parent bounds.
+        assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 4907bdc..d6ec788 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -190,7 +190,7 @@
     public void testCalculateSnapshotFrame() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 0, 10);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         assertEquals(new Rect(0, 0, 100, 80),
                 mSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
     }
@@ -199,7 +199,7 @@
     public void testCalculateSnapshotFrame_navBarLeft() {
         setupSurface(100, 100);
         final Rect insets = new Rect(10, 10, 0, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         assertEquals(new Rect(10, 0, 100, 90),
                 mSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
     }
@@ -208,7 +208,7 @@
     public void testCalculateSnapshotFrame_waterfall() {
         setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
         final Rect insets = new Rect(0, 10, 0, 10);
-        mSurface.setFrames(new Rect(5, 0, 95, 100), insets, insets);
+        mSurface.setFrames(new Rect(5, 0, 95, 100), insets);
         assertEquals(new Rect(0, 0, 90, 90),
                 mSurface.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
     }
@@ -217,7 +217,7 @@
     public void testDrawStatusBarBackground() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
@@ -230,7 +230,7 @@
     public void testDrawStatusBarBackground_nullFrame() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
@@ -243,7 +243,7 @@
     public void testDrawStatusBarBackground_nope() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
@@ -257,7 +257,7 @@
         final Rect insets = new Rect(0, 10, 0, 10);
         setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, 100, 100));
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
@@ -270,7 +270,7 @@
         final Rect insets = new Rect(10, 10, 0, 0);
         setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, 100, 100));
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
@@ -283,7 +283,7 @@
         final Rect insets = new Rect(0, 10, 10, 0);
         setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, 100, 100));
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b51784d..4a0f48cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -244,6 +245,12 @@
         appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
         assertTrue(appWindow.canBeImeTarget());
 
+        // Verify PINNED windows can't be IME target.
+        int initialMode = appWindow.mActivityRecord.getWindowingMode();
+        appWindow.mActivityRecord.setWindowingMode(WINDOWING_MODE_PINNED);
+        assertFalse(appWindow.canBeImeTarget());
+        appWindow.mActivityRecord.setWindowingMode(initialMode);
+
         // Make windows invisible
         appWindow.hideLw(false /* doAnimation */);
         imeWindow.hideLw(false /* doAnimation */);
@@ -646,6 +653,7 @@
         final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1");
         win1.mHasSurface = true;
         win1.mSurfaceControl = mock(SurfaceControl.class);
+        win1.mAttrs.surfaceInsets.set(1, 2, 3, 4);
         win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0);
         win1.updateSurfacePosition(t);
         win1.getTransformationMatrix(values, matrix);
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 0fc9be3..6eba62e 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.net.RouteInfo.RTN_THROW;
+import static android.net.RouteInfo.RTN_UNICAST;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 
 import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
@@ -1282,4 +1284,20 @@
         assertTrue(lp.hasIpv6UnreachableDefaultRoute());
         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
     }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testRouteAddWithSameKey() throws Exception {
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("wlan0");
+        final IpPrefix v6 = new IpPrefix("64:ff9b::/96");
+        lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1280));
+        assertEquals(1, lp.getRoutes().size());
+        lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1500));
+        assertEquals(1, lp.getRoutes().size());
+        final IpPrefix v4 = new IpPrefix("192.0.2.128/25");
+        lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_UNICAST, 1460));
+        assertEquals(2, lp.getRoutes().size());
+        lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_THROW, 1460));
+        assertEquals(2, lp.getRoutes().size());
+    }
 }
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index 8204b49..60cac0b 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -25,6 +25,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -56,7 +57,7 @@
     private static final int INVALID_ROUTE_TYPE = -1;
 
     private InetAddress Address(String addr) {
-        return InetAddress.parseNumericAddress(addr);
+        return InetAddresses.parseNumericAddress(addr);
     }
 
     private IpPrefix Prefix(String prefix) {
@@ -391,4 +392,43 @@
         r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
         assertEquals(0, r.getMtu());
     }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testRouteKey() {
+        RouteInfo.RouteKey k1, k2;
+        // Only prefix, null gateway and null interface
+        k1 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
+        k2 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
+        assertEquals(k1, k2);
+        assertEquals(k1.hashCode(), k2.hashCode());
+
+        // With prefix, gateway and interface. Type and MTU does not affect RouteKey equality
+        k1 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
+                RTN_UNREACHABLE, 1450).getRouteKey();
+        k2 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
+                RouteInfo.RTN_UNICAST, 1400).getRouteKey();
+        assertEquals(k1, k2);
+        assertEquals(k1.hashCode(), k2.hashCode());
+
+        // Different scope IDs are ignored by the kernel, so we consider them equal here too.
+        k1 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%1"), "wlan0").getRouteKey();
+        k2 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%2"), "wlan0").getRouteKey();
+        assertEquals(k1, k2);
+        assertEquals(k1.hashCode(), k2.hashCode());
+
+        // Different prefix
+        k1 = new RouteInfo(Prefix("192.0.2.0/24"), null).getRouteKey();
+        k2 = new RouteInfo(Prefix("192.0.3.0/24"), null).getRouteKey();
+        assertNotEquals(k1, k2);
+
+        // Different gateway
+        k1 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), null).getRouteKey();
+        k2 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::2"), null).getRouteKey();
+        assertNotEquals(k1, k2);
+
+        // Different interface
+        k1 = new RouteInfo(Prefix("ff02::1/128"), null, "tun0").getRouteKey();
+        k2 = new RouteInfo(Prefix("ff02::1/128"), null, "tun1").getRouteKey();
+        assertNotEquals(k1, k2);
+    }
 }