Merge "Deprecate long-obsolete android:anyDensity" into rvc-dev
diff --git a/Android.bp b/Android.bp
index d75a311..fb14f86 100644
--- a/Android.bp
+++ b/Android.bp
@@ -271,7 +271,6 @@
 
         // etc.
         ":framework-javastream-protos",
-        ":framework-statslog-gen", // StatsLogInternal.java
         ":statslog-framework-java-gen", // FrameworkStatsLog.java
 
         // telephony annotations
@@ -282,7 +281,6 @@
 filegroup {
     name: "framework-updatable-sources",
     srcs: [
-        ":framework-appsearch-sources",
         ":framework-sdkextensions-sources",
         ":framework-statsd-sources",
         ":framework-tethering-srcs",
@@ -468,7 +466,6 @@
     defaults: ["framework-defaults"],
     srcs: [":framework-non-updatable-sources"],
     libs: [
-        "framework-appsearch-stubs",
         "framework-sdkextensions-stubs-systemapi",
         "framework-statsd-stubs-module_libs_api",
         "framework-permission-stubs-systemapi",
@@ -494,7 +491,6 @@
     visibility: [
         "//frameworks/base",
         // TODO(b/147128803) remove the below lines
-        "//frameworks/base/apex/appsearch/framework",
         "//frameworks/base/apex/blobstore/framework",
         "//frameworks/base/apex/jobscheduler/framework",
         "//frameworks/base/packages/Tethering/tests/unit",
@@ -516,7 +512,6 @@
     installable: false, // this lib is a build-only library
     static_libs: [
         "framework-minus-apex",
-        "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
         "framework-media-stubs-systemapi",
         "framework-mediaprovider-stubs-systemapi",
         "framework-permission-stubs-systemapi",
@@ -541,7 +536,6 @@
         "exoplayer2-extractor",
         "android.hardware.wifi-V1.0-java-constants",
     ],
-    libs: ["icing-java-proto-lite"],
     apex_available: ["//apex_available:platform"],
     visibility: [
         // DO NOT ADD ANY MORE ENTRIES TO THIS LIST
@@ -562,7 +556,6 @@
     libs: [
         "app-compat-annotations",
         "ext",
-        "icing-java-proto-lite",
         "unsupportedappusage",
     ],
 
@@ -617,13 +610,6 @@
 }
 
 genrule {
-    name: "framework-statslog-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --worksource",
-    out: ["android/util/StatsLogInternal.java"],
-}
-
-genrule {
     name: "statslog-framework-java-gen",
     tools: ["stats-log-api-gen"],
     cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
deleted file mode 100644
index b014fdc..0000000
--- a/apex/appsearch/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-apex {
-    name: "com.android.appsearch",
-    manifest: "apex_manifest.json",
-    java_libs: [
-        "framework-appsearch",
-        "service-appsearch",
-    ],
-    key: "com.android.appsearch.key",
-    certificate: ":com.android.appsearch.certificate",
-}
-
-apex_key {
-    name: "com.android.appsearch.key",
-    public_key: "com.android.appsearch.avbpubkey",
-    private_key: "com.android.appsearch.pem",
-}
-
-android_app_certificate {
-    name: "com.android.appsearch.certificate",
-    // This will use com.android.appsearch.x509.pem (the cert) and
-    // com.android.appsearch.pk8 (the private key)
-    certificate: "com.android.appsearch",
-}
diff --git a/apex/appsearch/apex_manifest.json b/apex/appsearch/apex_manifest.json
deleted file mode 100644
index 39a2d38..0000000
--- a/apex/appsearch/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.appsearch",
-  "version": 300000000
-}
diff --git a/apex/appsearch/com.android.appsearch.avbpubkey b/apex/appsearch/com.android.appsearch.avbpubkey
deleted file mode 100644
index 4e5acae9..0000000
--- a/apex/appsearch/com.android.appsearch.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.pem b/apex/appsearch/com.android.appsearch.pem
deleted file mode 100644
index 4ed5945..0000000
--- a/apex/appsearch/com.android.appsearch.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKQIBAAKCAgEAro9f/jvoIsj6ywuRmuUQS8UtprhohJitrovDMfm/T2R/WQvy
-AvUxgetyF4XvBPCDRqCsGxXCJMQOn1furrAeTmWbGHPhA0PI1Ys/qtfNMbh9THyn
-70I2c4X70CUQ+8/Y8BJ8CAB4iER/s9QtD28QLvM2BBUzRoKUSBGUYNMlYobjgRdK
-57V7yg48LkvUIg1fzIW3M5gCgOXa0u1xOadKX3m7tzCboHcXp5anfWX5PH1+okRu
-jzdI8OjtUq23qhoRw5Skz0Vbf4a+8t3kT3slF/Q7O8LoRPwpZsvIcvTyCGAqlra7
-2L2LN4H1p+u2ko3r/QmRbJn2eXW07elkyrggXMyn2rTxibQgk53wYfSavMyNd/E7
-+de/uJ60l2aPa+5KUaR8eYwchXEELdqQ+zRgSZ2711xCaY4glEj7DT6VlEEdr26x
-akX0ra7e2sVGv1um/dvSyVO5aFKKjVvo4LqhWKWO8yvDMxmDDTNatvWhY2Bhd3RA
-0hilYpWQFb9Tv5f4E0tZmfvlddgux7sw++Y/RIimBFoSyf5AezAUIFYYoYvEzytB
-muq1/ecNHr+Z2tZMxN88sJVhzRzD9tKUyXhvxOV2Lg9TIeVTWGwQqgSnHWtIe+1p
-cw8inPfYEhP4Q+3W/RlPvNdu75x8Nj2aG7bxZnhoQDRDw5ddgma27I+a8esCAwEA
-AQKCAgBsNh9I6HRAVBz8kCBkSEnw3rwtFTZdtJQ+lw+bRHpvShqT5g7R/JQDOSTS
-JkoE4uBOgT4P0E45Inz6FLW2/yDacqxR3UwJDRVMI/WFACCJCRhLuR8V+BLvTIjN
-AJ1lrPSL5rmS8E/IEcakgQyp+6ypnkXHBCl0NXCcuKEl4N7VFE+mb/0UZPHnUSnH
-fWR085uGmwH17u7mXxdnGKDPH8DALSPMLUrcj9dPIdqUpwl5kUZWa1uqVphWF98/
-GMe5oE2Q0+3TO+i7xplKz3lAOFPHZLTvmCUK1tMHkZ6ifOwpewwLwB30/5N1BpB1
-126nrWk0xKCtFUixBOHzdnLwJHKSbi7chQU5q39oAJoTfxdmAJlaG0zQHUQZ44MQ
-gemzSA7uJbtoAOAZVF1K14xbIpnfidqTB7N3RCmiJE+/Hpkq6PxgPfu5rqocPbPC
-t0FgJ4NXNmKOAuJllSlrrHATcUOhF4g5pX7tvOc8X4y7bvfwOmtw5ez3INKMF0q6
-/y0vVCi6N1Z7CTa9eY8feZ1PImk/Fkq4NInSPyx7ZE3pLYmsvuJjliFrWo9TRVae
-Dt5vvBKBOpAfhDiHkeXbX7Raj2B6c6adF4no/3SAVlAjIq1iBVjfQWyHAGUoEW1O
-u3LdHTIb6gSTLJ4AfryEKrOE+1VMlYt92GwX692KKXMaJjytSQKCAQEA3pYbl8HD
-Y++UyEN5VzWAQedT3//GDwpDfgdERe2E4smYrkVNJ2WAG2SqY1A35DIl8be3eHvl
-soaL38j48ailfDYY9tI+IlapNh+VOLej+HiOytaPlLhcv2FpSC2qZT4EiU6IBXLo
-+l6FrmD/VQXTjvoktzsDB/n1t4Dfa3Ogf+lLf1Jxr94YpEnDh18V5ofj78SplVLm
-NrzsHxAafE4Ni2a7dyWjcDYIuL7FTShT+0K4W45tRr+CGxThxu7LEe7zw4Z1IagU
-jJNtXjvDD/Zw4UTqI6RwWGZsu6UjPS6LHhOqnWqflWmFRIfMbDkuWvnGZTM9DkVg
-kk1+BNi1PECZXwKCAQEAyMOjbVo6XV3lFN0X8TpHyg/z9ar00/SE7WEJHqPSuzYT
-rSfU4vDDlaPAwkYvGi9ZKi9VM+R3CyBNxnK9Yq6NurHhhrYcAwdS/hGLT1K2o0Y8
-Pgv7gZCFb+SIwLBhlUG9otGULcBzLneqgVUqyMG6IoCjuC2LRyB71Xc2UMyg6n/f
-XpV2RTMb8f+26cgm6nj0SDAfgpr8HV6uNV80c6l1A8gq86nUWwiVAEUdmExSDe7J
-shsfWAj8RSErqDXf1BtEdPLJUSIPX5VXkzAXOXIkengwVno0vv0dBN8uraS8iQSG
-0JsJLLcw9b5kvnh6FEbE7POsIqKyCZV9VADwO6YW9QKCAQBYQsdwNqoGv6KMgozj
-8tgHyfWtVduwbQ50M+dznwpZbzz2pY5Bd/MDabhSpyVyfBwlrAa5ZM+hKc7fDu7/
-zDLKfR0LCjUPIrP4PS/LjK4dQZjFf6zxeOV2EedQcqMlgCEGXTh8iKMvXDm/+sBk
-c2n/QNs8OM8r44b2m8h78B6NefGw6/0ekn/M7V72F9M0VWAh3Cauim+09tbePmFy
-NvUR+MuPJEKZpSNyNltADCS49izqSSC1tAygNniMjHXDh6/rMS7TCLYVRARTIHlp
-o/wAp3X8aiEOPJcTFRlTElihtYSq5POgqHXqxbpek5H5CyALUvT76rCvcsDspQ3A
-dZEbAoIBAQCoLEmP5o8Rev/UdEgECB/uwWJIngYsLp3TAv/SrMRvkiL1X3JTD/+m
-L9/eXVBDjPoR/khPCcg2h77ex2qhaTrL8wnKAG6CkvYQYb3impTnPIRmLT9nDxrX
-2gY78wQrNUCXTRvlH1rcx90KLb+DH9S95ig+tdf/otRYwl27XU5GYQtJfcXuvZth
-IiWku8btjpiCh909WHpsV81yY+faI08j9d8U8WQzRYMbEMpzsyrhBO/rxBCDfDNl
-7R1W8JooYRb9KAs/bVqXZNBROW2a72RjOp6zMfdRLVHLrPC7AE32MNaFk/khfesD
-T5OwgdcxeP6oxo2hDcw5fwHXBlo2fTCpAoIBAQChgjv5AfQ50spqvHy6MNem4tV0
-L0IsxmNLsi8X2a6s4kStwUzOxDA8c/e54XabxQNZ0ERU1q+bgbG7PWC4twDMPR8i
-2DO6rgqSK4MjGOTgAoeDuy3mElFQmCLRs04Wf4jh8kPi217WFlYBynh2HmBKbh42
-JmIrLetbKEK13FXRvMkgZcX4OIDrT5TOvev4VZArU8PTRlWv3sqsKAVXjX0clGHf
-I0/2kSsr2qq1UY7JrYWZsZ9uqz2ZH0pF19a6O/Cq4uqTYoL+sYzFTSeFmChRjV1g
-ancTvTn9lcBqECDMgq5DE/p96Oxg/t8elalR6WDUlysafphVz3nTuyMTh7ka
------END RSA PRIVATE KEY-----
diff --git a/apex/appsearch/com.android.appsearch.pk8 b/apex/appsearch/com.android.appsearch.pk8
deleted file mode 100644
index 77e98b2..0000000
--- a/apex/appsearch/com.android.appsearch.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.x509.pem b/apex/appsearch/com.android.appsearch.x509.pem
deleted file mode 100644
index e37c4b9..0000000
--- a/apex/appsearch/com.android.appsearch.x509.pem
+++ /dev/null
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGETCCA/mgAwIBAgIUGl+MIvpEi0+TWzj0ieh6WtjXmP8wDQYJKoZIhvcNAQEL
-BQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMRIwEAYDVQQDDAlhcHBzZWFyY2gxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRA
-YW5kcm9pZC5jb20wIBcNMTkxMTIwMjMxNTM1WhgPNDc1NzEwMTYyMzE1MzVaMIGW
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDES
-MBAGA1UEAwwJYXBwc2VhcmNoMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJv
-aWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsyPlp3q3P9Xg
-W1WhIwQiF9em9oqaGQ/3dbIxickAy591qcRbpHb4lDTZusRECfqlV215mV+lv5x4
-EhOnId3uPKBAJ/YDtL7zUW6TWL7to7zEnUqSIKTcoQzNF2EiCeGuRhrtgYvAD3HQ
-dwr4xrbSADbDArF04A49voLpsmq1fyNgl86VISiMRqoSLJnA6eghlduuOt+nf252
-6WgxDs/JrO/eK70q0+RwmWzVJ/tVr+36a65N4EHhfL4t2hdV0k0XFob7hBn7XWzC
-QrSR3jCvE3yAfAr3tq5c19/WWBA7V45nEHzXyAvBUHWubYvDi+vm/yzqU2rQwScC
-bzp4zK4CnhBHqb4gHoy0+kfFIwJ1A3GT2pl3ba/NsIYgliMtPQfkDV5PE5RTNcwH
-21ewH7vm2+spQv5Z/2TEV2lEHlp2vuAliyn2AT4u1ginr6vtBRFLmpPeziFcfB0y
-7h04GctZpX8odz+XI7aMDe47RNu9XyJX0vulntxmlDF76k8Z9DIXg02hY+yc/i7+
-2ztnj1eXL51p+HyhK5VbvJWbKkVaMQijlbuIMYNzMA6L0WHWRc2Cux9UDODMGoiC
-w09JpqudCS/95I/F1xaWJ/Kh3vKeQshHAz0hrL7v7wpjmfeXf6NGsWJGy+giCwZj
-ABtn9nFQoesgi7M1LeazD5Q/4v4AMaUCAwEAAaNTMFEwHQYDVR0OBBYEFJpHCy2Y
-3qaL6cLpE9fe53L61KEEMB8GA1UdIwQYMBaAFJpHCy2Y3qaL6cLpE9fe53L61KEE
-MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAGDYAcOhbOYcDB2K
-WDZka+FCORFFvz4nLQGE7Z9TAn1g7XusM2KbXlb2drIN6CWOFlnKQrUsNsAHrc+s
-tl+A1vC3/NfYKKBVuizPx/kHUgz3k/UIJzbzEu/uCJd86idcJoUTqC/qEJAeeQqM
-XpsNP1Yg7oyzZT8sFlUAKeDeXJ7fIDXR6nduUQ6uJXkee/5JF3VedHdgHAUsC19/
-KHhyVU3MLDUNBdAmM79+DsdVYi2Pw31jojMu95Zz1MYTRBcgQAiEw5nncr38k6ac
-Gy+JffgJR68FzI4QLBSxnDRFD2zXJ09lpP6Sjb1FVcDzk7Bi/EQDLBkrkbeLsk5F
-a0xz9VoJ3kM7Cc4R9MXN4ZWuePjdJwgasnHmllsXn45R9odgJgmfzuUwtgNw/XKQ
-QcQl7Q9QUrBCqIoHijxscUZCBSmIHVNBBDckRAmSXHeWMRlO3uBR4IA/Jfrt//4f
-uc7CNUp+LQ6EzBXJOVFrXRtau6Oj+jM1+fzxKo1uV2+T+GdVEE5jeF/6nB3qna6h
-2NmyLqbqeqp2QxgzBWSGy8Ugs6zg4wItJBqOoRLKKFxTJu5OAzJ4fUA+g7WFXNhR
-kG56SJ863LZoORKHWE72oXYeIW98Tq0qKLH3NzH5L4tfX8DeBTq+APezHetH1ljA
-D0avPy62g0i643bbpwZgezBgRIKL
------END CERTIFICATE-----
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
deleted file mode 100644
index 24309d7..0000000
--- a/apex/appsearch/framework/Android.bp
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-filegroup {
-    name: "framework-appsearch-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-    ],
-    path: "java",
-}
-
-java_library {
-    name: "framework-appsearch",
-    installable: true,
-    sdk_version: "core_platform", // TODO(b/146218515) should be core_current
-    srcs: [":framework-appsearch-sources"],
-    hostdex: true, // for hiddenapi check
-    libs: [
-        "framework-minus-apex",  // TODO(b/146218515) should be framework-system-stubs
-    ],
-    static_libs: ["icing-java-proto-lite"],
-    visibility: [
-        // TODO(b/146218515) remove this when framework is built with the stub of appsearch
-        "//frameworks/base",
-        "//frameworks/base/apex/appsearch:__subpackages__",
-    ],
-    permitted_packages: ["android.app.appsearch"],
-    apex_available: ["com.android.appsearch"],
-}
-
-metalava_appsearch_docs_args =
-    "--hide-package com.android.server " +
-    "--error UnhiddenSystemApi " +
-    "--hide RequiresPermission " +
-    "--hide MissingPermission " +
-    "--hide BroadcastBehavior " +
-    "--hide HiddenSuperclass " +
-    "--hide DeprecationMismatch " +
-    "--hide UnavailableSymbol " +
-    "--hide SdkConstant " +
-    "--hide HiddenTypeParameter " +
-    "--hide Todo --hide Typo " +
-    "--hide HiddenTypedefConstant " +
-    "--show-annotation android.annotation.SystemApi "
-
-droidstubs {
-    name: "framework-appsearch-stubs-srcs",
-    srcs: [
-        ":framework-annotations",
-        ":framework-appsearch-sources",
-    ],
-    aidl: {
-        include_dirs: ["frameworks/base/core/java"],
-    },
-    args: metalava_appsearch_docs_args,
-    sdk_version: "core_current",
-    libs: ["android_system_stubs_current"],
-}
-
-java_library {
-    name: "framework-appsearch-stubs",
-    srcs: [":framework-appsearch-stubs-srcs"],
-    aidl: {
-        export_include_dirs: [
-            "java",
-        ],
-    },
-    sdk_version: "core_current",
-    libs: ["android_system_stubs_current"],
-    installable: false,
-}
diff --git a/apex/appsearch/framework/java/android/app/TEST_MAPPING b/apex/appsearch/framework/java/android/app/TEST_MAPPING
deleted file mode 100644
index 12188f8..0000000
--- a/apex/appsearch/framework/java/android/app/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "imports": [
-    {
-      "path": "frameworks/base/apex/appsearch/service/java/com/android/server/appsearch"
-    }
-  ]
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
deleted file mode 100644
index 773db93..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArrayMap;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Provides access to multiple results from a batch operation accepting multiple inputs.
- *
- * @param <KeyType> The type of the keys for {@link #getResults} and {@link #getFailures}.
- * @param <ValueType> The type of result objects associated with the keys.
- * @hide
- */
-public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
-    @NonNull private final Map<KeyType, ValueType> mResults;
-    @NonNull private final Map<KeyType, Throwable> mFailures;
-
-    private AppSearchBatchResult(
-            @NonNull Map<KeyType, ValueType> results, @NonNull Map<KeyType, Throwable> failures) {
-        mResults = results;
-        mFailures = failures;
-    }
-
-    private AppSearchBatchResult(@NonNull Parcel in) {
-        mResults = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
-        mFailures = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeMap(mResults);
-        dest.writeMap(mFailures);
-    }
-
-    /** Returns {@code true} if this {@link AppSearchBatchResult} has no failures. */
-    public boolean isSuccess() {
-        return mFailures.isEmpty();
-    }
-
-    /**
-     * Returns a {@link Map} of all successful keys mapped to the results they produced.
-     *
-     * <p>The values of the {@link Map} may be {@code null}.
-     */
-    @NonNull
-    public Map<KeyType, ValueType> getResults() {
-        return mResults;
-    }
-
-    /**
-     * Returns a {@link Map} of all failed keys mapped to a {@link Throwable} representing the cause
-     * of failure.
-     *
-     * <p>The values of the {@link Map} may be {@code null}.
-     */
-    @NonNull
-    public Map<KeyType, Throwable> getFailures() {
-        return mFailures;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Creator<AppSearchBatchResult> CREATOR =
-            new Creator<AppSearchBatchResult>() {
-        @NonNull
-        @Override
-        public AppSearchBatchResult createFromParcel(@NonNull Parcel in) {
-            return new AppSearchBatchResult(in);
-        }
-
-        @NonNull
-        @Override
-        public AppSearchBatchResult[] newArray(int size) {
-            return new AppSearchBatchResult[size];
-        }
-    };
-
-    /**
-     * Creates a new {@link Builder} for this {@link AppSearchBatchResult}.
-     * @hide
-     */
-    @NonNull
-    public static <KeyType, ValueType> Builder<KeyType, ValueType> newBuilder() {
-        return new Builder<>();
-    }
-
-    /**
-     * Builder for {@link AppSearchBatchResult} objects.
-     *
-     * @param <KeyType> The type of keys.
-     * @param <ValueType> The type of result objects associated with the keys.
-     * @hide
-     */
-    public static final class Builder<KeyType, ValueType> {
-        @NonNull private final Map<KeyType, ValueType> mResults = new ArrayMap<>();
-        @NonNull private final Map<KeyType, Throwable> mFailures = new ArrayMap<>();
-
-        private Builder() {}
-
-        /**
-         * Registers that the {@code key} was processed successfully and associates it with
-         * {@code value}. Any previous mapping for a key, whether success or failure, is deleted.
-         */
-        public Builder setSuccess(@NonNull KeyType key, @Nullable ValueType value) {
-            mResults.put(key, value);
-            mFailures.remove(key);
-            return this;
-        }
-
-        /**
-         * Registers that the {@code key} failed and associates it with {@code throwable}. Any
-         * previous mapping for a key, whether success or failure, is deleted.
-         */
-        public Builder setFailure(@NonNull KeyType key, @Nullable Throwable throwable) {
-            mFailures.put(key, throwable);
-            mResults.remove(key);
-            return this;
-        }
-
-        /** Builds an {@link AppSearchBatchResult} from the contents of this {@link Builder}. */
-        @NonNull
-        public AppSearchBatchResult<KeyType, ValueType> build() {
-            return new AppSearchBatchResult<>(mResults, mFailures);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
deleted file mode 100644
index ff0f0dd..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.CurrentTimeMillisLong;
-import android.annotation.DurationMillisLong;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Preconditions;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Represents a document unit.
- *
- * <p>Documents are constructed via {@link AppSearchDocument.Builder}.
- * @hide
- */
-public class AppSearchDocument {
-    private static final String TAG = "AppSearchDocument";
-
-    /**
-     * The maximum number of elements in a repeatable field. Will reject the request if exceed
-     * this limit.
-     */
-    private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
-
-    /**
-     * The maximum {@link String#length} of a {@link String} field. Will reject the request if
-     * {@link String}s longer than this.
-     */
-    private static final int MAX_STRING_LENGTH = 20_000;
-
-    /**
-     * Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and properties
-     * ordered by keys.
-     */
-    @NonNull
-    private final DocumentProto mProto;
-
-    /** Contains all properties in {@link #mProto} to support getting properties via keys. */
-    @NonNull
-    private final Map<String, Object> mProperties;
-
-    /**
-     * Create a new {@link AppSearchDocument}.
-     * @param proto Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and
-     *               properties ordered by keys.
-     * @param propertiesMap Contains all properties in {@link #mProto} to support get properties
-     *                      via keys.
-     */
-    private AppSearchDocument(@NonNull DocumentProto proto,
-            @NonNull Map<String, Object> propertiesMap) {
-        mProto = proto;
-        mProperties = propertiesMap;
-    }
-
-    /**
-     * Create a new {@link AppSearchDocument} from an existing instance.
-     *
-     * <p>This method should be only used by constructor of a subclass.
-     */
-    protected AppSearchDocument(@NonNull AppSearchDocument document) {
-        this(document.mProto, document.mProperties);
-    }
-
-    /** @hide */
-    AppSearchDocument(@NonNull DocumentProto documentProto) {
-        this(documentProto, new ArrayMap<>());
-        for (int i = 0; i < documentProto.getPropertiesCount(); i++) {
-            PropertyProto property = documentProto.getProperties(i);
-            String name = property.getName();
-            if (property.getStringValuesCount() > 0) {
-                String[] values = new String[property.getStringValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getStringValues(j);
-                }
-                mProperties.put(name, values);
-            } else if (property.getInt64ValuesCount() > 0) {
-                long[] values = new long[property.getInt64ValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getInt64Values(j);
-                }
-                mProperties.put(property.getName(), values);
-            } else if (property.getDoubleValuesCount() > 0) {
-                double[] values = new double[property.getDoubleValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getDoubleValues(j);
-                }
-                mProperties.put(property.getName(), values);
-            } else if (property.getBooleanValuesCount() > 0) {
-                boolean[] values = new boolean[property.getBooleanValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getBooleanValues(j);
-                }
-                mProperties.put(property.getName(), values);
-            } else if (property.getBytesValuesCount() > 0) {
-                byte[][] values = new byte[property.getBytesValuesCount()][];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getBytesValues(j).toByteArray();
-                }
-                mProperties.put(name, values);
-            } else if (property.getDocumentValuesCount() > 0) {
-                AppSearchDocument[] values =
-                        new AppSearchDocument[property.getDocumentValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = new AppSearchDocument(property.getDocumentValues(j));
-                }
-                mProperties.put(name, values);
-            } else {
-                throw new IllegalStateException("Unknown type of value: " + name);
-            }
-        }
-    }
-
-    /**
-     * Get the {@link DocumentProto} of the {@link AppSearchDocument}.
-     *
-     * <p>The {@link DocumentProto} contains {@link AppSearchDocument}'s basic information and all
-     *    properties ordered by keys.
-     * @hide
-     */
-    @NonNull
-    @VisibleForTesting
-    public DocumentProto getProto() {
-        return mProto;
-    }
-
-    /**
-     * Get the uri of the {@link AppSearchDocument}.
-     *
-     * @hide
-     */
-    @NonNull
-    public String getUri() {
-        return mProto.getUri();
-    }
-
-    /**
-     * Get the schema type of the {@link AppSearchDocument}.
-     * @hide
-     */
-    @NonNull
-    public String getSchemaType() {
-        return mProto.getSchema();
-    }
-
-    /**
-     * Get the creation timestamp in milliseconds of the {@link AppSearchDocument}. Value will be in
-     * the {@link System#currentTimeMillis()} time base.
-     *
-     * @hide
-     */
-    @CurrentTimeMillisLong
-    public long getCreationTimestampMillis() {
-        return mProto.getCreationTimestampMs();
-    }
-
-    /**
-     * Returns the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds.
-     *
-     * <p>The default value is 0, which means the document is permanent and won't be auto-deleted
-     *    until the app is uninstalled.
-     *
-     * @hide
-     */
-    @DurationMillisLong
-    public long getTtlMillis() {
-        return mProto.getTtlMs();
-    }
-
-    /**
-     * Returns the score of the {@link AppSearchDocument}.
-     *
-     * <p>The score is a query-independent measure of the document's quality, relative to other
-     * {@link AppSearchDocument}s of the same type.
-     *
-     * <p>The default value is 0.
-     *
-     * @hide
-     */
-    public int getScore() {
-        return mProto.getScore();
-    }
-
-    /**
-     * Retrieve a {@link String} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link String} associated with the given key or {@code null} if there
-     *         is no such key or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public String getPropertyString(@NonNull String key) {
-        String[] propertyArray = getPropertyStringArray(key);
-        if (ArrayUtils.isEmpty(propertyArray)) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("String", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieve a {@link Long} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link Long} associated with the given key or {@code null} if there
-     *         is no such key or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public Long getPropertyLong(@NonNull String key) {
-        long[] propertyArray = getPropertyLongArray(key);
-        if (ArrayUtils.isEmpty(propertyArray)) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("Long", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieve a {@link Double} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link Double} associated with the given key or {@code null} if there
-     *         is no such key or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public Double getPropertyDouble(@NonNull String key) {
-        double[] propertyArray = getPropertyDoubleArray(key);
-        // TODO(tytytyww): Add support double array to ArraysUtils.isEmpty().
-        if (propertyArray == null || propertyArray.length == 0) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("Double", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieve a {@link Boolean} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link Boolean} associated with the given key or {@code null} if there
-     *         is no such key or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public Boolean getPropertyBoolean(@NonNull String key) {
-        boolean[] propertyArray = getPropertyBooleanArray(key);
-        if (ArrayUtils.isEmpty(propertyArray)) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieve a {@code byte[]} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@code byte[]} associated with the given key or {@code null} if there
-     *         is no such key or the value is of a different type.
-     */
-    @Nullable
-    public byte[] getPropertyBytes(@NonNull String key) {
-        byte[][] propertyArray = getPropertyBytesArray(key);
-        if (ArrayUtils.isEmpty(propertyArray)) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieve a {@link AppSearchDocument} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link AppSearchDocument} associated with the given key or {@code null} if
-     *         there is no such key or the value is of a different type.
-     */
-    @Nullable
-    public AppSearchDocument getPropertyDocument(@NonNull String key) {
-        AppSearchDocument[] propertyArray = getPropertyDocumentArray(key);
-        if (ArrayUtils.isEmpty(propertyArray)) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("Document", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /** Prints a warning to logcat if the given propertyLength is greater than 1. */
-    private static void warnIfSinglePropertyTooLong(
-            @NonNull String propertyType, @NonNull String key, int propertyLength) {
-        if (propertyLength > 1) {
-            Log.w(TAG, "The value for \"" + key + "\" contains " + propertyLength
-                    + " elements. Only the first one will be returned from "
-                    + "getProperty" + propertyType + "(). Try getProperty" + propertyType
-                    + "Array().");
-        }
-    }
-
-    /**
-     * Retrieve a repeated {@code String} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code String[]} associated with the given key, or {@code null} if no value
-     *         is set or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public String[] getPropertyStringArray(@NonNull String key) {
-        return getAndCastPropertyArray(key, String[].class);
-    }
-
-    /**
-     * Retrieve a repeated {@code long} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code long[]} associated with the given key, or {@code null} if no value is
-     *         set or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public long[] getPropertyLongArray(@NonNull String key) {
-        return getAndCastPropertyArray(key, long[].class);
-    }
-
-    /**
-     * Retrieve a repeated {@code double} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code double[]} associated with the given key, or {@code null} if no value
-     *         is set or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public double[] getPropertyDoubleArray(@NonNull String key) {
-        return getAndCastPropertyArray(key, double[].class);
-    }
-
-    /**
-     * Retrieve a repeated {@code boolean} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code boolean[]} associated with the given key, or {@code null} if no value
-     *         is set or the value is of a different type.
-     * @hide
-     */
-    @Nullable
-    public boolean[] getPropertyBooleanArray(@NonNull String key) {
-        return getAndCastPropertyArray(key, boolean[].class);
-    }
-
-    /**
-     * Retrieve a {@code byte[][]} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code byte[][]} associated with the given key, or {@code null} if no value
-     *         is set or the value is of a different type.
-     */
-    @Nullable
-    public byte[][] getPropertyBytesArray(@NonNull String key) {
-        return getAndCastPropertyArray(key, byte[][].class);
-    }
-
-    /**
-     * Retrieve a repeated {@link AppSearchDocument} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@link AppSearchDocument[]} associated with the given key, or {@code null} if no
-     *         value is set or the value is of a different type.
-     */
-    @Nullable
-    public AppSearchDocument[] getPropertyDocumentArray(@NonNull String key) {
-        return getAndCastPropertyArray(key, AppSearchDocument[].class);
-    }
-
-    /**
-     * Gets a repeated property of the given key, and casts it to the given class type, which
-     * must be an array class type.
-     */
-    @Nullable
-    private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) {
-        Object value = mProperties.get(key);
-        if (value == null) {
-            return null;
-        }
-        try {
-            return tClass.cast(value);
-        } catch (ClassCastException e) {
-            Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e);
-            return null;
-        }
-    }
-
-    @Override
-    public boolean equals(@Nullable Object other) {
-        // Check only proto's equality is sufficient here since all properties in
-        // mProperties are ordered by keys and stored in proto.
-        if (this == other) {
-            return true;
-        }
-        if (!(other instanceof AppSearchDocument)) {
-            return false;
-        }
-        AppSearchDocument otherDocument = (AppSearchDocument) other;
-        return this.mProto.equals(otherDocument.mProto);
-    }
-
-    @Override
-    public int hashCode() {
-        // Hash only proto is sufficient here since all properties in mProperties are ordered by
-        // keys and stored in proto.
-        return mProto.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return mProto.toString();
-    }
-
-    /**
-     * The builder class for {@link AppSearchDocument}.
-     *
-     * @param <BuilderType> Type of subclass who extend this.
-     * @hide
-     */
-    public static class Builder<BuilderType extends Builder> {
-
-        private final Map<String, Object> mProperties = new ArrayMap<>();
-        private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
-        private final BuilderType mBuilderTypeInstance;
-
-        /**
-         * Create a new {@link AppSearchDocument.Builder}.
-         *
-         * @param uri The uri of {@link AppSearchDocument}.
-         * @param schemaType The schema type of the {@link AppSearchDocument}. The passed-in
-         *       {@code schemaType} must be defined using {@link AppSearchManager#setSchema} prior
-         *       to inserting a document of this {@code schemaType} into the AppSearch index using
-         *       {@link AppSearchManager#putDocuments(List)}. Otherwise, the document will be
-         *       rejected by {@link AppSearchManager#putDocuments(List)}.
-         * @hide
-         */
-        public Builder(@NonNull String uri, @NonNull String schemaType) {
-            mBuilderTypeInstance = (BuilderType) this;
-            mProtoBuilder.setUri(uri).setSchema(schemaType);
-            // Set current timestamp for creation timestamp by default.
-            setCreationTimestampMillis(System.currentTimeMillis());
-        }
-
-        /**
-         * Sets the score of the {@link AppSearchDocument}.
-         *
-         * <p>The score is a query-independent measure of the document's quality, relative to
-         * other {@link AppSearchDocument}s of the same type.
-         *
-         * @throws IllegalArgumentException If the provided value is negative.
-         * @hide
-         */
-        @NonNull
-        public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) {
-            if (score < 0) {
-                throw new IllegalArgumentException("Document score cannot be negative.");
-            }
-            mProtoBuilder.setScore(score);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Set the creation timestamp in milliseconds of the {@link AppSearchDocument}. Should be
-         * set using a value obtained from the {@link System#currentTimeMillis()} time base.
-         *
-         * @hide
-         */
-        @NonNull
-        public BuilderType setCreationTimestampMillis(
-                @CurrentTimeMillisLong long creationTimestampMillis) {
-            mProtoBuilder.setCreationTimestampMs(creationTimestampMillis);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Set the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds.
-         *
-         * <p>After this many milliseconds since the {@link #setCreationTimestampMillis(long)}
-         * creation timestamp}, the document is deleted.
-         *
-         * @param ttlMillis A non-negative duration in milliseconds.
-         * @throws IllegalArgumentException If the provided value is negative.
-         */
-        @NonNull
-        public BuilderType setTtlMillis(@DurationMillisLong long ttlMillis) {
-            Preconditions.checkArgumentNonNegative(
-                    ttlMillis, "Document ttlMillis cannot be negative.");
-            mProtoBuilder.setTtlMs(ttlMillis);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code String} values for a property, replacing its previous
-         * values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code String} values of the property.
-         * @hide
-         */
-        @NonNull
-        public BuilderType setProperty(@NonNull String key, @NonNull String... values) {
-            putInPropertyMap(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code boolean} values for a property, replacing its previous
-         * values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code boolean} values of the property.
-         */
-        @NonNull
-        public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) {
-            putInPropertyMap(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code long} values for a property, replacing its previous
-         * values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code long} values of the property.
-         */
-        @NonNull
-        public BuilderType setProperty(@NonNull String key, @NonNull long... values) {
-            putInPropertyMap(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code double} values for a property, replacing its previous
-         * values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code double} values of the property.
-         */
-        @NonNull
-        public BuilderType setProperty(@NonNull String key, @NonNull double... values) {
-            putInPropertyMap(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code byte[]} for a property, replacing its previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code byte[]} of the property.
-         */
-        @NonNull
-        public BuilderType setProperty(@NonNull String key, @NonNull byte[]... values) {
-            putInPropertyMap(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@link AppSearchDocument} values for a property, replacing its
-         * previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@link AppSearchDocument} values of the property.
-         */
-        @NonNull
-        public BuilderType setProperty(@NonNull String key, @NonNull AppSearchDocument... values) {
-            putInPropertyMap(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        private void putInPropertyMap(@NonNull String key, @NonNull String[] values)
-                throws IllegalArgumentException {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(values);
-            validateRepeatedPropertyLength(key, values.length);
-            for (int i = 0; i < values.length; i++) {
-                if (values[i] == null) {
-                    throw new IllegalArgumentException("The String at " + i + " is null.");
-                } else if (values[i].length() > MAX_STRING_LENGTH) {
-                    throw new IllegalArgumentException("The String at " + i + " length is: "
-                            + values[i].length()  + ", which exceeds length limit: "
-                            + MAX_STRING_LENGTH + ".");
-                }
-            }
-            mProperties.put(key, values);
-        }
-
-        private void putInPropertyMap(@NonNull String key, @NonNull boolean[] values) {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(values);
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
-        }
-
-        private void putInPropertyMap(@NonNull String key, @NonNull double[] values) {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(values);
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
-        }
-
-        private void putInPropertyMap(@NonNull String key, @NonNull long[] values) {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(values);
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
-        }
-
-        private void putInPropertyMap(@NonNull String key, @NonNull byte[][] values) {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(values);
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
-        }
-
-        private void putInPropertyMap(@NonNull String key, @NonNull AppSearchDocument[] values) {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(values);
-            for (int i = 0; i < values.length; i++) {
-                if (values[i] == null) {
-                    throw new IllegalArgumentException("The document at " + i + " is null.");
-                }
-            }
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
-        }
-
-        private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
-            if (length == 0) {
-                throw new IllegalArgumentException("The input array is empty.");
-            } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
-                throw new IllegalArgumentException(
-                        "Repeated property \"" + key + "\" has length " + length
-                                + ", which exceeds the limit of "
-                                + MAX_REPEATED_PROPERTY_LENGTH);
-            }
-        }
-
-        /**
-         * Builds the {@link AppSearchDocument} object.
-         * @hide
-         */
-        public AppSearchDocument build() {
-            // Build proto by sorting the keys in mProperties to exclude the influence of
-            // order. Therefore documents will generate same proto as long as the contents are
-            // same. Note that the order of repeated fields is still preserved.
-            ArrayList<String> keys = new ArrayList<>(mProperties.keySet());
-            Collections.sort(keys);
-            for (int i = 0; i < keys.size(); i++) {
-                String name = keys.get(i);
-                Object values = mProperties.get(name);
-                PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
-                if (values instanceof boolean[]) {
-                    for (boolean value : (boolean[]) values) {
-                        propertyProto.addBooleanValues(value);
-                    }
-                } else if (values instanceof long[]) {
-                    for (long value : (long[]) values) {
-                        propertyProto.addInt64Values(value);
-                    }
-                } else if (values instanceof double[]) {
-                    for (double value : (double[]) values) {
-                        propertyProto.addDoubleValues(value);
-                    }
-                } else if (values instanceof String[]) {
-                    for (String value : (String[]) values) {
-                        propertyProto.addStringValues(value);
-                    }
-                } else if (values instanceof AppSearchDocument[]) {
-                    for (AppSearchDocument value : (AppSearchDocument[]) values) {
-                        propertyProto.addDocumentValues(value.getProto());
-                    }
-                } else if (values instanceof byte[][]) {
-                    for (byte[] value : (byte[][]) values) {
-                        propertyProto.addBytesValues(ByteString.copyFrom(value));
-                    }
-                } else {
-                    throw new IllegalStateException(
-                            "Property \"" + name + "\" has unsupported value type \""
-                                    + values.getClass().getSimpleName() + "\"");
-                }
-                mProtoBuilder.addProperties(propertyProto);
-            }
-            return new AppSearchDocument(mProtoBuilder.build(), mProperties);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java
deleted file mode 100644
index 5b9457b..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.appsearch.AppSearchSchema.PropertyConfig;
-
-/**
- * Encapsulates a {@link AppSearchDocument} that represent an email.
- *
- * <p>This class is a higher level implement of {@link AppSearchDocument}.
- *
- * <p>This class will eventually migrate to Jetpack, where it will become public API.
- *
- * @hide
- */
-public class AppSearchEmail extends AppSearchDocument {
-    private static final String KEY_FROM = "from";
-    private static final String KEY_TO = "to";
-    private static final String KEY_CC = "cc";
-    private static final String KEY_BCC = "bcc";
-    private static final String KEY_SUBJECT = "subject";
-    private static final String KEY_BODY = "body";
-
-    /** The name of the schema type for {@link AppSearchEmail} documents.*/
-    public static final String SCHEMA_TYPE = "builtin:Email";
-
-    public static final AppSearchSchema SCHEMA = AppSearchSchema.newBuilder(SCHEMA_TYPE)
-            .addProperty(AppSearchSchema.newPropertyBuilder(KEY_FROM)
-                    .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                    .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                    .build()
-
-            ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_TO)
-                    .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                    .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
-                    .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                    .build()
-
-            ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_CC)
-                    .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                    .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
-                    .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                    .build()
-
-            ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BCC)
-                    .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                    .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
-                    .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                    .build()
-
-            ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_SUBJECT)
-                    .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                    .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                    .build()
-
-            ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BODY)
-                    .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                    .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                    .build()
-
-            ).build();
-
-    /**
-     * Creates a new {@link AppSearchEmail} from the contents of an existing
-     * {@link AppSearchDocument}.
-     *
-     * @param document The {@link AppSearchDocument} containing the email content.
-     */
-    public AppSearchEmail(@NonNull AppSearchDocument document) {
-        super(document);
-    }
-
-    /**
-     * Get the from address of {@link AppSearchEmail}.
-     *
-     * @return Returns the subject of {@link AppSearchEmail} or {@code null} if it's not been set
-     *         yet.
-     * @hide
-     */
-    @Nullable
-    public String getFrom() {
-        return getPropertyString(KEY_FROM);
-    }
-
-    /**
-     * Get the destination addresses of {@link AppSearchEmail}.
-     *
-     * @return Returns the destination addresses of {@link AppSearchEmail} or {@code null} if it's
-     *         not been set yet.
-     * @hide
-     */
-    @Nullable
-    public String[] getTo() {
-        return getPropertyStringArray(KEY_TO);
-    }
-
-    /**
-     * Get the CC list of {@link AppSearchEmail}.
-     *
-     * @return Returns the CC list of {@link AppSearchEmail} or {@code null} if it's not been set
-     *         yet.
-     * @hide
-     */
-    @Nullable
-    public String[] getCc() {
-        return getPropertyStringArray(KEY_CC);
-    }
-
-    /**
-     * Get the BCC list of {@link AppSearchEmail}.
-     *
-     * @return Returns the BCC list of {@link AppSearchEmail} or {@code null} if it's not been set
-     *         yet.
-     * @hide
-     */
-    @Nullable
-    public String[] getBcc() {
-        return getPropertyStringArray(KEY_BCC);
-    }
-
-    /**
-     * Get the subject of {@link AppSearchEmail}.
-     *
-     * @return Returns the value subject of {@link AppSearchEmail} or {@code null} if it's not been
-     *         set yet.
-     * @hide
-     */
-    @Nullable
-    public String getSubject() {
-        return getPropertyString(KEY_SUBJECT);
-    }
-
-    /**
-     * Get the body of {@link AppSearchEmail}.
-     *
-     * @return Returns the body of {@link AppSearchEmail} or {@code null} if it's not been set yet.
-     * @hide
-     */
-    @Nullable
-    public String getBody() {
-        return getPropertyString(KEY_BODY);
-    }
-
-    /**
-     * The builder class for {@link AppSearchEmail}.
-     * @hide
-     */
-    public static class Builder extends AppSearchDocument.Builder<AppSearchEmail.Builder> {
-
-        /**
-         * Create a new {@link AppSearchEmail.Builder}
-         * @param uri The Uri of the Email.
-         * @hide
-         */
-        public Builder(@NonNull String uri) {
-            super(uri, SCHEMA_TYPE);
-        }
-
-        /**
-         * Set the from address of {@link AppSearchEmail}
-         * @hide
-         */
-        @NonNull
-        public AppSearchEmail.Builder setFrom(@NonNull String from) {
-            setProperty(KEY_FROM, from);
-            return this;
-        }
-
-        /**
-         * Set the destination address of {@link AppSearchEmail}
-         * @hide
-         */
-        @NonNull
-        public AppSearchEmail.Builder setTo(@NonNull String... to) {
-            setProperty(KEY_TO, to);
-            return this;
-        }
-
-        /**
-         * Set the CC list of {@link AppSearchEmail}
-         * @hide
-         */
-        @NonNull
-        public AppSearchEmail.Builder setCc(@NonNull String... cc) {
-            setProperty(KEY_CC, cc);
-            return this;
-        }
-
-        /**
-         * Set the BCC list of {@link AppSearchEmail}
-         * @hide
-         */
-        @NonNull
-        public AppSearchEmail.Builder setBcc(@NonNull String... bcc) {
-            setProperty(KEY_BCC, bcc);
-            return this;
-        }
-
-        /**
-         * Set the subject of {@link AppSearchEmail}
-         * @hide
-         */
-        @NonNull
-        public AppSearchEmail.Builder setSubject(@NonNull String subject) {
-            setProperty(KEY_SUBJECT, subject);
-            return this;
-        }
-
-        /**
-         * Set the body of {@link AppSearchEmail}
-         * @hide
-         */
-        @NonNull
-        public AppSearchEmail.Builder setBody(@NonNull String body) {
-            setProperty(KEY_BODY, body);
-            return this;
-        }
-
-        /**
-         * Builds the {@link AppSearchEmail} object.
-         *
-         * @hide
-         */
-        @NonNull
-        @Override
-        public AppSearchEmail build() {
-            return new AppSearchEmail(super.build());
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
deleted file mode 100644
index e2c9b0f..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.os.RemoteException;
-
-import com.android.internal.infra.AndroidFuture;
-
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.proto.StatusProto;
-import com.google.android.icing.protobuf.InvalidProtocolBufferException;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
-
-/**
- * This class provides access to the centralized AppSearch index maintained by the system.
- *
- * <p>Apps can index structured text documents with AppSearch, which can then be retrieved through
- * the query API.
- *
- * @hide
- */
-@SystemService(Context.APP_SEARCH_SERVICE)
-public class AppSearchManager {
-    private final IAppSearchManager mService;
-
-    /** @hide */
-    public AppSearchManager(@NonNull IAppSearchManager service) {
-        mService = service;
-    }
-
-    /**
-     * Sets the schema being used by documents provided to the {@link #putDocuments} method.
-     *
-     * <p>The schema provided here is compared to the stored copy of the schema previously supplied
-     * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
-     * types of schema modifications are always safe and are made without deleting any existing
-     * documents:
-     * <ul>
-     *     <li>Addition of new types
-     *     <li>Addition of new
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
-     *             OPTIONAL} or
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
-     *             REPEATED} properties to a type
-     *     <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
-     *             OPTIONAL} property into a
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
-     *             REPEATED} property.
-     * </ul>
-     *
-     * <p>The following types of schema changes are not backwards-compatible. Supplying a schema
-     * with such changes will result in this call throwing an {@link IllegalSchemaException}
-     * describing the incompatibility, and the previously set schema will remain active:
-     * <ul>
-     *     <li>Removal of an existing type
-     *     <li>Removal of a property from a type
-     *     <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
-     *     <li>For properties of {@code Document} type, changing the schema type of
-     *         {@code Document Documents} of that property
-     *     <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
-     *             OPTIONAL} property into a
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
-     *             REQUIRED} property).
-     *     <li>Adding a
-     *         {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
-     *             REQUIRED} property.
-     * </ul>
-     *
-     * <p>If you need to make non-backwards-compatible changes as described above, instead use the
-     * {@link #setSchema(List, boolean)} method with the {@code forceOverride} parameter set to
-     * {@code true}.
-     *
-     * <p>It is a no-op to set the same schema as has been previously set; this is handled
-     * efficiently.
-     *
-     * @param schemas The schema configs for the types used by the calling app.
-     * @throws IllegalSchemaException If the provided schema is invalid, or is incompatible with the
-     *     previous schema.
-     *
-     * @hide
-     */
-    public void setSchema(@NonNull AppSearchSchema... schemas) {
-        setSchema(Arrays.asList(schemas), /*forceOverride=*/false);
-    }
-
-    /**
-     * Sets the schema being used by documents provided to the {@link #putDocuments} method.
-     *
-     * <p>This method is similar to {@link #setSchema(AppSearchSchema...)}, except for the
-     * {@code forceOverride} parameter. If a backwards-incompatible schema is specified but the
-     * {@code forceOverride} parameter is set to {@code true}, instead of throwing an
-     * {@link IllegalSchemaException}, all documents which are not compatible with the new schema
-     * will be deleted and the incompatible schema will be applied.
-     *
-     * @param schemas The schema configs for the types used by the calling app.
-     * @param forceOverride Whether to force the new schema to be applied even if there are
-     *     incompatible changes versus the previously set schema. Documents which are incompatible
-     *     with the new schema will be deleted.
-     * @throws IllegalSchemaException If the provided schema is invalid, or is incompatible with the
-     *     previous schema and the {@code forceOverride} parameter is set to {@code false}.
-     *
-     * @hide
-     */
-    public void setSchema(@NonNull List<AppSearchSchema> schemas, boolean forceOverride) {
-        // Prepare the merged schema for transmission.
-        SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder();
-        for (AppSearchSchema schema : schemas) {
-            schemaProtoBuilder.addTypes(schema.getProto());
-        }
-
-        // Serialize and send the schema.
-        // TODO: This should use com.android.internal.infra.RemoteStream or another mechanism to
-        //  avoid binder limits.
-        byte[] schemaBytes = schemaProtoBuilder.build().toByteArray();
-        AndroidFuture<Void> future = new AndroidFuture<>();
-        try {
-            mService.setSchema(schemaBytes, forceOverride, future);
-        } catch (RemoteException e) {
-            future.completeExceptionally(e);
-        }
-        getFutureOrThrow(future);
-    }
-
-    /**
-     * Index {@link AppSearchDocument Documents} into AppSearch.
-     *
-     * <p>You should not call this method directly; instead, use the
-     * {@code AppSearch#putDocuments()} API provided by JetPack.
-     *
-     * <p>Each {@link AppSearchDocument Document's} {@code schemaType} field must be set to the
-     * name of a schema type previously registered via the {@link #setSchema} method.
-     *
-     * @param documents {@link AppSearchDocument Documents} that need to be indexed.
-     * @return An {@link AppSearchBatchResult} mapping the document URIs to {@link Void} if they
-     *     were successfully indexed, or a {@link Throwable} describing the failure if they could
-     *     not be indexed.
-     * @hide
-     */
-    public AppSearchBatchResult<String, Void> putDocuments(
-            @NonNull List<AppSearchDocument> documents) {
-        // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in
-        // one big list.
-        List<byte[]> documentsBytes = new ArrayList<>(documents.size());
-        for (AppSearchDocument document : documents) {
-            documentsBytes.add(document.getProto().toByteArray());
-        }
-        AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
-        try {
-            mService.putDocuments(documentsBytes, future);
-        } catch (RemoteException e) {
-            future.completeExceptionally(e);
-        }
-        return getFutureOrThrow(future);
-    }
-
-    /**
-     * This method searches for documents based on a given query string. It also accepts
-     * specifications regarding how to search and format the results.
-     *
-     *<p>Currently we support following features in the raw query format:
-     * <ul>
-     *     <li>AND
-     *     <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
-     *     ‘cat’”).
-     *     Example: hello world matches documents that have both ‘hello’ and ‘world’
-     *     <li>OR
-     *     <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
-     *     ‘cat’”).
-     *     Example: dog OR puppy
-     *     <li>Exclusion
-     *     <p>Exclude a term (e.g. “match documents that do
-     *     not have the term ‘dog’”).
-     *     Example: -dog excludes the term ‘dog’
-     *     <li>Grouping terms
-     *     <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
-     *     “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
-     *     Example: (dog puppy) (cat kitten) two one group containing two terms.
-     *     <li>Property restricts
-     *     <p> Specifies which properties of a document to specifically match terms in (e.g.
-     *     “match documents where the ‘subject’ property contains ‘important’”).
-     *     Example: subject:important matches documents with the term ‘important’ in the
-     *     ‘subject’ property
-     *     <li>Schema type restricts
-     *     <p>This is similar to property restricts, but allows for restricts on top-level document
-     *     fields, such as schema_type. Clients should be able to limit their query to documents of
-     *     a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
-     *     Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
-     *     that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
-     *     ‘Video’ schema type.
-     * </ul>
-     *
-     * <p> It is strongly recommended to use Jetpack APIs.
-     *
-     * @param queryExpression Query String to search.
-     * @param searchSpec Spec for setting filters, raw query etc.
-     * @param executor Executor on which to invoke the callback.
-     * @param callback  Callback to receive errors resulting from the query operation. If the
-     *                 operation succeeds, the callback will be invoked with {@code null}.
-     * @hide
-     */
-    @NonNull
-    public void query(
-            @NonNull String queryExpression,
-            @NonNull SearchSpec searchSpec,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull BiConsumer<? super SearchResults, ? super Throwable> callback) {
-        AndroidFuture<byte[]> future = new AndroidFuture<>();
-        future.whenCompleteAsync((searchResultBytes, err) -> {
-            if (err != null) {
-                callback.accept(null, err);
-                return;
-            }
-
-            if (searchResultBytes != null) {
-                SearchResultProto searchResultProto;
-                try {
-                    searchResultProto = SearchResultProto.parseFrom(searchResultBytes);
-                } catch (InvalidProtocolBufferException e) {
-                    callback.accept(null, e);
-                    return;
-                }
-                if (searchResultProto.getStatus().getCode() != StatusProto.Code.OK) {
-                    // TODO(sidchhabra): Add better exception handling.
-                    callback.accept(
-                            null,
-                            new RuntimeException(searchResultProto.getStatus().getMessage()));
-                    return;
-                }
-                SearchResults searchResults = new SearchResults(searchResultProto);
-                callback.accept(searchResults, null);
-                return;
-            }
-
-            // Nothing was supplied in the future at all
-            callback.accept(
-                    null, new IllegalStateException("Unknown failure occurred while querying"));
-        }, executor);
-
-        try {
-            SearchSpecProto searchSpecProto = searchSpec.getSearchSpecProto();
-            searchSpecProto = searchSpecProto.toBuilder().setQuery(queryExpression).build();
-            mService.query(searchSpecProto.toByteArray(),
-                    searchSpec.getResultSpecProto().toByteArray(),
-                    searchSpec.getScoringSpecProto().toByteArray(), future);
-        } catch (RemoteException e) {
-            future.completeExceptionally(e);
-        }
-    }
-
-    private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) {
-        try {
-            return future.get();
-        } catch (Throwable e) {
-            if (e instanceof ExecutionException) {
-                e = e.getCause();
-            }
-            if (e instanceof RuntimeException) {
-                throw (RuntimeException) e;
-            }
-            if (e instanceof Error) {
-                throw (Error) e;
-            }
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
deleted file mode 100644
index 02cc967..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-import android.annotation.SystemApi;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-
-/**
- * Class holding initialization code for the AppSearch module.
- *
- * @hide
- */
-@SystemApi
-public class AppSearchManagerFrameworkInitializer {
-    private AppSearchManagerFrameworkInitializer() {}
-
-    /**
-     * Called by {@link SystemServiceRegistry}'s static initializer and registers all AppSearch
-     * services to {@link Context}, so that {@link Context#getSystemService} can return them.
-     *
-     * @throws IllegalStateException if this is called from anywhere besides
-     *     {@link SystemServiceRegistry}
-     */
-    public static void initialize() {
-        SystemServiceRegistry.registerStaticService(
-                Context.APP_SEARCH_SERVICE, AppSearchManager.class,
-                (service) -> new AppSearchManager(IAppSearchManager.Stub.asInterface(service)));
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
deleted file mode 100644
index 1d54dc4..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-
-/**
- * The AppSearch Schema for a particular type of document.
- *
- * <p>For example, an e-mail message or a music recording could be a schema type.
- *
- * <p>The schema consists of type information, properties, and config (like tokenization type).
- *
- * @hide
- */
-public final class AppSearchSchema {
-    private final SchemaTypeConfigProto mProto;
-
-    private AppSearchSchema(SchemaTypeConfigProto proto) {
-        mProto = proto;
-    }
-
-    /** Creates a new {@link AppSearchSchema.Builder}. */
-    @NonNull
-    public static AppSearchSchema.Builder newBuilder(@NonNull String typeName) {
-        return new AppSearchSchema.Builder(typeName);
-    }
-
-    /** Creates a new {@link PropertyConfig.Builder}. */
-    @NonNull
-    public static PropertyConfig.Builder newPropertyBuilder(@NonNull String propertyName) {
-        return new PropertyConfig.Builder(propertyName);
-    }
-
-    /**
-     * Returns the {@link SchemaTypeConfigProto} populated by this builder.
-     * @hide
-     */
-    @NonNull
-    @VisibleForTesting
-    public SchemaTypeConfigProto getProto() {
-        return mProto;
-    }
-
-    @Override
-    public String toString() {
-        return mProto.toString();
-    }
-
-    /** Builder for {@link AppSearchSchema objects}. */
-    public static final class Builder {
-        private final SchemaTypeConfigProto.Builder mProtoBuilder =
-                SchemaTypeConfigProto.newBuilder();
-
-        private Builder(@NonNull String typeName) {
-            mProtoBuilder.setSchemaType(typeName);
-        }
-
-        /** Adds a property to the given type. */
-        @NonNull
-        public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
-            mProtoBuilder.addProperties(propertyConfig.mProto);
-            return this;
-        }
-
-        /**
-         * Constructs a new {@link AppSearchSchema} from the contents of this builder.
-         *
-         * <p>After calling this method, the builder must no longer be used.
-         */
-        @NonNull
-        public AppSearchSchema build() {
-            Set<String> propertyNames = new ArraySet<>();
-            for (PropertyConfigProto propertyConfigProto : mProtoBuilder.getPropertiesList()) {
-                if (!propertyNames.add(propertyConfigProto.getPropertyName())) {
-                    throw new IllegalSchemaException(
-                            "Property defined more than once: "
-                                    + propertyConfigProto.getPropertyName());
-                }
-            }
-            return new AppSearchSchema(mProtoBuilder.build());
-        }
-    }
-
-    /**
-     * Configuration for a single property (field) of a document type.
-     *
-     * <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be
-     * a property.
-     */
-    public static final class PropertyConfig {
-        /** Physical data-types of the contents of the property. */
-        // NOTE: The integer values of these constants must match the proto enum constants in
-        // com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
-        @IntDef(prefix = {"DATA_TYPE_"}, value = {
-                DATA_TYPE_STRING,
-                DATA_TYPE_INT64,
-                DATA_TYPE_DOUBLE,
-                DATA_TYPE_BOOLEAN,
-                DATA_TYPE_BYTES,
-                DATA_TYPE_DOCUMENT,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface DataType {}
-
-        public static final int DATA_TYPE_STRING = 1;
-        public static final int DATA_TYPE_INT64 = 2;
-        public static final int DATA_TYPE_DOUBLE = 3;
-        public static final int DATA_TYPE_BOOLEAN = 4;
-
-        /** Unstructured BLOB. */
-        public static final int DATA_TYPE_BYTES = 5;
-
-        /**
-         * Indicates that the property itself is an Document, making it part a hierarchical
-         * Document schema. Any property using this DataType MUST have a valid
-         * {@code schemaType}.
-         */
-        public static final int DATA_TYPE_DOCUMENT = 6;
-
-        /** The cardinality of the property (whether it is required, optional or repeated). */
-        // NOTE: The integer values of these constants must match the proto enum constants in
-        // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
-        @IntDef(prefix = {"CARDINALITY_"}, value = {
-                CARDINALITY_REPEATED,
-                CARDINALITY_OPTIONAL,
-                CARDINALITY_REQUIRED,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Cardinality {}
-
-        /** Any number of items (including zero) [0...*]. */
-        public static final int CARDINALITY_REPEATED = 1;
-
-        /** Zero or one value [0,1]. */
-        public static final int CARDINALITY_OPTIONAL = 2;
-
-        /** Exactly one value [1]. */
-        public static final int CARDINALITY_REQUIRED = 3;
-
-        /** Encapsulates the configurations on how AppSearch should query/index these terms. */
-        @IntDef(prefix = {"INDEXING_TYPE_"}, value = {
-                INDEXING_TYPE_NONE,
-                INDEXING_TYPE_EXACT_TERMS,
-                INDEXING_TYPE_PREFIXES,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface IndexingType {}
-
-        /**
-         * Content in this property will not be tokenized or indexed.
-         *
-         * <p>Useful if the data type is not made up of terms (e.g.
-         * {@link PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES}
-         * type). All the properties inside the nested property won't be indexed regardless of the
-         * value of {@code indexingType} for the nested properties.
-         */
-        public static final int INDEXING_TYPE_NONE = 0;
-
-        /**
-         * Content in this property should only be returned for queries matching the exact tokens
-         * appearing in this property.
-         *
-         * <p>Ex. A property with "fool" should NOT match a query for "foo".
-         */
-        public static final int INDEXING_TYPE_EXACT_TERMS = 1;
-
-        /**
-         * Content in this property should be returned for queries that are either exact matches or
-         * query matches of the tokens appearing in this property.
-         *
-         * <p>Ex. A property with "fool" <b>should</b> match a query for "foo".
-         */
-        public static final int INDEXING_TYPE_PREFIXES = 2;
-
-        /** Configures how tokens should be extracted from this property. */
-        // NOTE: The integer values of these constants must match the proto enum constants in
-        // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
-        @IntDef(prefix = {"TOKENIZER_TYPE_"}, value = {
-                TOKENIZER_TYPE_NONE,
-                TOKENIZER_TYPE_PLAIN,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface TokenizerType {}
-
-        /**
-         * It is only valid for tokenizer_type to be 'NONE' if the data type is
-         * {@link PropertyConfig#DATA_TYPE_DOCUMENT}.
-         */
-        public static final int TOKENIZER_TYPE_NONE = 0;
-
-        /** Tokenization for plain text. */
-        public static final int TOKENIZER_TYPE_PLAIN = 1;
-
-        private final PropertyConfigProto mProto;
-
-        private PropertyConfig(PropertyConfigProto proto) {
-            mProto = proto;
-        }
-
-        @Override
-        public String toString() {
-            return mProto.toString();
-        }
-
-        /**
-         * Builder for {@link PropertyConfig}.
-         *
-         * <p>The following properties must be set, or {@link PropertyConfig} construction will
-         * fail:
-         * <ul>
-         *     <li>dataType
-         *     <li>cardinality
-         * </ul>
-         *
-         * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
-         * is also required.
-         */
-        public static final class Builder {
-            private final PropertyConfigProto.Builder mPropertyConfigProto =
-                    PropertyConfigProto.newBuilder();
-            private final com.google.android.icing.proto.IndexingConfig.Builder
-                    mIndexingConfigProto =
-                        com.google.android.icing.proto.IndexingConfig.newBuilder();
-
-            private Builder(String propertyName) {
-                mPropertyConfigProto.setPropertyName(propertyName);
-            }
-
-            /**
-             * Type of data the property contains (e.g. string, int, bytes, etc).
-             *
-             * <p>This property must be set.
-             */
-            @NonNull
-            public PropertyConfig.Builder setDataType(@DataType int dataType) {
-                PropertyConfigProto.DataType.Code dataTypeProto =
-                        PropertyConfigProto.DataType.Code.forNumber(dataType);
-                if (dataTypeProto == null) {
-                    throw new IllegalArgumentException("Invalid dataType: " + dataType);
-                }
-                mPropertyConfigProto.setDataType(dataTypeProto);
-                return this;
-            }
-
-            /**
-             * The logical schema-type of the contents of this property.
-             *
-             * <p>Only required when {@link #setDataType(int)} is set to
-             * {@link #DATA_TYPE_DOCUMENT}. Otherwise, it is ignored.
-             */
-            @NonNull
-            public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
-                mPropertyConfigProto.setSchemaType(schemaType);
-                return this;
-            }
-
-            /**
-             * The cardinality of the property (whether it is optional, required or repeated).
-             *
-             * <p>This property must be set.
-             */
-            @NonNull
-            public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                PropertyConfigProto.Cardinality.Code cardinalityProto =
-                        PropertyConfigProto.Cardinality.Code.forNumber(cardinality);
-                if (cardinalityProto == null) {
-                    throw new IllegalArgumentException("Invalid cardinality: " + cardinality);
-                }
-                mPropertyConfigProto.setCardinality(cardinalityProto);
-                return this;
-            }
-
-            /**
-             * Configures how a property should be indexed so that it can be retrieved by queries.
-             */
-            @NonNull
-            public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
-                TermMatchType.Code termMatchTypeProto;
-                switch (indexingType) {
-                    case INDEXING_TYPE_NONE:
-                        termMatchTypeProto = TermMatchType.Code.UNKNOWN;
-                        break;
-                    case INDEXING_TYPE_EXACT_TERMS:
-                        termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
-                        break;
-                    case INDEXING_TYPE_PREFIXES:
-                        termMatchTypeProto = TermMatchType.Code.PREFIX;
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
-                }
-                mIndexingConfigProto.setTermMatchType(termMatchTypeProto);
-                return this;
-            }
-
-            /** Configures how this property should be tokenized (split into words). */
-            @NonNull
-            public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
-                com.google.android.icing.proto.IndexingConfig.TokenizerType.Code
-                        tokenizerTypeProto =
-                            com.google.android.icing.proto.IndexingConfig
-                                .TokenizerType.Code.forNumber(tokenizerType);
-                if (tokenizerTypeProto == null) {
-                    throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
-                }
-                mIndexingConfigProto.setTokenizerType(tokenizerTypeProto);
-                return this;
-            }
-
-            /**
-             * Constructs a new {@link PropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalSchemaException If the property is not correctly populated (e.g.
-             *     missing {@code dataType}).
-             */
-            @NonNull
-            public PropertyConfig build() {
-                mPropertyConfigProto.setIndexingConfig(mIndexingConfigProto);
-                // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
-                //     of partially reimplementing some of the validation Icing does here.
-                if (mPropertyConfigProto.getDataType()
-                        == PropertyConfigProto.DataType.Code.UNKNOWN) {
-                    throw new IllegalSchemaException("Missing field: dataType");
-                }
-                if (mPropertyConfigProto.getSchemaType().isEmpty()
-                        && mPropertyConfigProto.getDataType()
-                            == PropertyConfigProto.DataType.Code.DOCUMENT) {
-                    throw new IllegalSchemaException(
-                            "Missing field: schemaType (required for configs with "
-                                    + "dataType = DOCUMENT)");
-                }
-                if (mPropertyConfigProto.getCardinality()
-                        == PropertyConfigProto.Cardinality.Code.UNKNOWN) {
-                    throw new IllegalSchemaException("Missing field: cardinality");
-                }
-                return new PropertyConfig(mPropertyConfigProto.build());
-            }
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
deleted file mode 100644
index eef41ed..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * Copyright 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-import com.android.internal.infra.AndroidFuture;
-
-parcelable AppSearchBatchResult;
-
-/** {@hide} */
-interface IAppSearchManager {
-    /**
-     * Sets the schema.
-     *
-     * @param schemaBytes Serialized SchemaProto.
-     * @param forceOverride Whether to apply the new schema even if it is incompatible. All
-     *     incompatible documents will be deleted.
-     * @param callback {@link AndroidFuture}&lt;{@link Void}&gt;. Will be completed with
-     *     {@code null} upon successful completion of the setSchema call, or completed
-     *     exceptionally if setSchema fails.
-     */
-    void setSchema(in byte[] schemaBytes, boolean forceOverride, in AndroidFuture callback);
-
-    /**
-     * Inserts documents into the index.
-     *
-     * @param documentsBytes {@link List}&lt;byte[]&gt; of serialized DocumentProtos.
-     * @param callback
-     *     {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;&gt;.
-     *     If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
-     *     {@code callback} will be completed with an
-     *     {@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;
-     *     where the keys are document URIs, and the values are {@code null}.
-     */
-    void putDocuments(in List documentsBytes, in AndroidFuture<AppSearchBatchResult> callback);
-
-    /**
-     * Searches a document based on a given specifications.
-     *
-     * @param searchSpecBytes Serialized SearchSpecProto.
-     * @param resultSpecBytes Serialized SearchResultsProto.
-     * @param scoringSpecBytes Serialized ScoringSpecProto.
-     * @param callback {@link AndroidFuture}. Will be completed with a serialized
-     *     {@link SearchResultsProto}, or completed exceptionally if query fails.
-     */
-    void query(in byte[] searchSpecBytes, in byte[] resultSpecBytes,
-            in byte[] scoringSpecBytes, in AndroidFuture callback);
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java b/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java
deleted file mode 100644
index f9e528c..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-
-/**
- * Indicates that a {@link android.app.appsearch.AppSearchSchema} has logical inconsistencies such
- * as unpopulated mandatory fields or illegal combinations of parameters.
- *
- * @hide
- */
-public class IllegalSchemaException extends IllegalArgumentException {
-    /**
-     * Constructs a new {@link IllegalSchemaException}.
-     *
-     * @param message A developer-readable description of the issue with the bundle.
-     */
-    public IllegalSchemaException(@NonNull String message) {
-        super(message);
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java b/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java
deleted file mode 100644
index 0d029f0..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-
-/**
- * Indicates that a {@link android.app.appsearch.SearchResults} has logical inconsistencies such
- * as unpopulated mandatory fields or illegal combinations of parameters.
- *
- * @hide
- */
-public class IllegalSearchSpecException extends IllegalArgumentException {
-    /**
-     * Constructs a new {@link IllegalSearchSpecException}.
-     *
-     * @param message A developer-readable description of the issue with the bundle.
-     */
-    public IllegalSearchSpecException(@NonNull String message) {
-        super(message);
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java
deleted file mode 100644
index 5ce2960..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.util.Range;
-
-import com.google.android.icing.proto.SnippetMatchProto;
-
-/**
- * Snippet: It refers to a substring of text from the content of document that is returned as a
- * part of search result.
- * This class represents a match objects for any Snippets that might be present in
- * {@link SearchResults} from query. Using this class user can get the full text, exact matches and
- * Snippets of document content for a given match.
- *
- * <p>Class Example 1:
- * A document contains following text in property subject:
- * <p>A commonly used fake word is foo. Another nonsense word that’s used a lot is bar.
- *
- * <p>If the queryExpression is "foo".
- *
- * <p>{@link MatchInfo#getPropertyPath()} returns "subject"
- * <p>{@link MatchInfo#getFullText()} returns "A commonly used fake word is foo. Another nonsense
- * word that’s used a lot is bar."
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [29, 32]
- * <p>{@link MatchInfo#getExactMatch()} returns "foo"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [29, 41]
- * <p>{@link MatchInfo#getSnippet()} returns "is foo. Another"
- * <p>
- * <p>Class Example 2:
- * A document contains a property name sender which contains 2 property names name and email, so
- * we will have 2 property paths: {@code sender.name} and {@code sender.email}.
- * <p> Let {@code sender.name = "Test Name Jr."} and {@code sender.email = "TestNameJr@gmail.com"}
- *
- * <p>If the queryExpression is "Test". We will have 2 matches.
- *
- * <p> Match-1
- * <p>{@link MatchInfo#getPropertyPath()} returns "sender.name"
- * <p>{@link MatchInfo#getFullText()} returns "Test Name Jr."
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 4]
- * <p>{@link MatchInfo#getExactMatch()} returns "Test"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 9]
- * <p>{@link MatchInfo#getSnippet()} returns "Test Name Jr."
- * <p> Match-2
- * <p>{@link MatchInfo#getPropertyPath()} returns "sender.email"
- * <p>{@link MatchInfo#getFullText()} returns "TestNameJr@gmail.com"
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 20]
- * <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20]
- * <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com"
- * @hide
- */
-// TODO(sidchhabra): Capture real snippet after integration with icingLib.
-public final class MatchInfo {
-
-    private final String mPropertyPath;
-    private final SnippetMatchProto mSnippetMatch;
-    private final AppSearchDocument mDocument;
-    /**
-     * List of content with same property path in a document when there are multiple matches in
-     * repeated sections.
-     */
-    private final String[] mValues;
-
-    /** @hide */
-    public MatchInfo(@NonNull String propertyPath, @NonNull SnippetMatchProto snippetMatch,
-            @NonNull AppSearchDocument document) {
-        mPropertyPath = propertyPath;
-        mSnippetMatch = snippetMatch;
-        mDocument = document;
-        // In IcingLib snippeting is available for only 3 data types i.e String, double and long,
-        // so we need to check which of these three are requested.
-        // TODO (sidchhabra): getPropertyStringArray takes property name, handle for property path.
-        String[] values = mDocument.getPropertyStringArray(propertyPath);
-        if (values == null) {
-            values = doubleToString(mDocument.getPropertyDoubleArray(propertyPath));
-        }
-        if (values == null) {
-            values = longToString(mDocument.getPropertyLongArray(propertyPath));
-        }
-        if (values == null) {
-            throw new IllegalStateException("No content found for requested property path!");
-        }
-        mValues = values;
-    }
-
-    /**
-     * Gets the property path corresponding to the given entry.
-     * <p>Property Path: '.' - delimited sequence of property names indicating which property in
-     * the Document these snippets correspond to.
-     * <p>Example properties: 'body', 'sender.name', 'sender.emailaddress', etc.
-     * For class example 1 this returns "subject"
-     */
-    @NonNull
-    public String getPropertyPath() {
-        return mPropertyPath;
-    }
-
-    /**
-     * Gets the full text corresponding to the given entry.
-     * <p>For class example this returns "A commonly used fake word is foo. Another nonsense word
-     * that’s used a lot is bar."
-     */
-    @NonNull
-    public String getFullText() {
-        return mValues[mSnippetMatch.getValuesIndex()];
-    }
-
-    /**
-     * Gets the exact match range corresponding to the given entry.
-     * <p>For class example 1 this returns [29, 32]
-     */
-    @NonNull
-    public Range getExactMatchPosition() {
-        return new Range(mSnippetMatch.getExactMatchPosition(),
-                mSnippetMatch.getExactMatchPosition() + mSnippetMatch.getExactMatchBytes());
-    }
-
-    /**
-     * Gets the exact match corresponding to the given entry.
-     * <p>For class example 1 this returns "foo"
-     */
-    @NonNull
-    public CharSequence getExactMatch() {
-        return getSubstring(getExactMatchPosition());
-    }
-
-    /**
-     * Gets the snippet range corresponding to the given entry.
-     * <p>For class example 1 this returns [29, 41]
-     */
-    @NonNull
-    public Range getSnippetPosition() {
-        return new Range(mSnippetMatch.getWindowPosition(),
-                mSnippetMatch.getWindowPosition() + mSnippetMatch.getWindowBytes());
-    }
-
-    /**
-     * Gets the snippet corresponding to the given entry.
-     * <p>Snippet - Provides a subset of the content to display. The
-     * length of this content can be changed {@link SearchSpec.Builder#setMaxSnippetSize(int)}.
-     * Windowing is centered around the middle of the matched token with content on either side
-     * clipped to token boundaries.
-     * <p>For class example 1 this returns "foo. Another"
-     */
-    @NonNull
-    public CharSequence getSnippet() {
-        return getSubstring(getSnippetPosition());
-    }
-
-    private CharSequence getSubstring(Range range) {
-        return getFullText()
-                .substring((int) range.getLower(), (int) range.getUpper());
-    }
-
-    /** Utility method to convert double[] to String[] */
-    private String[] doubleToString(double[] values) {
-        //TODO(sidchhabra): Implement the method.
-        return null;
-    }
-
-    /** Utility method to convert long[] to String[] */
-    private String[] longToString(long[] values) {
-        //TODO(sidchhabra): Implement the method.
-        return null;
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
deleted file mode 100644
index 7287fe6..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SnippetMatchProto;
-import com.google.android.icing.proto.SnippetProto;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * SearchResults are a list of results that are returned from a query. Each result from this
- * list contains a document and may contain other fields like snippets based on request.
- * This iterator class is not thread safe.
- * @hide
- */
-public final class SearchResults implements Iterator<SearchResults.Result> {
-
-    private final SearchResultProto mSearchResultProto;
-    private int mNextIdx;
-
-    /** @hide */
-    public SearchResults(SearchResultProto searchResultProto) {
-        mSearchResultProto = searchResultProto;
-    }
-
-    @Override
-    public boolean hasNext() {
-        return mNextIdx < mSearchResultProto.getResultsCount();
-    }
-
-    @NonNull
-    @Override
-    public Result next() {
-        if (!hasNext()) {
-            throw new NoSuchElementException();
-        }
-        Result result = new Result(mSearchResultProto.getResults(mNextIdx));
-        mNextIdx++;
-        return result;
-    }
-
-
-
-    /**
-     * This class represents the result obtained from the query. It will contain the document which
-     * which matched the specified query string and specifications.
-     * @hide
-     */
-    public static final class Result {
-        private final SearchResultProto.ResultProto mResultProto;
-
-        @Nullable
-        private AppSearchDocument mDocument;
-
-        private Result(SearchResultProto.ResultProto resultProto) {
-            mResultProto = resultProto;
-        }
-
-        /**
-         * Contains the matching {@link AppSearchDocument}.
-         * @return Document object which matched the query.
-         * @hide
-         */
-        @NonNull
-        public AppSearchDocument getDocument() {
-            if (mDocument == null) {
-                mDocument = new AppSearchDocument(mResultProto.getDocument());
-            }
-            return mDocument;
-        }
-
-        /**
-         * Contains a list of Snippets that matched the request. Only populated when requested in
-         * {@link SearchSpec.Builder#setMaxSnippetSize(int)}.
-         * @return  List of matches based on {@link SearchSpec}, if snippeting is disabled and this
-         * method is called it will return {@code null}. Users can also restrict snippet population
-         * using {@link SearchSpec.Builder#setNumToSnippet} and
-         * {@link SearchSpec.Builder#setNumMatchesPerProperty}, for all results after that value
-         * this method will return {@code null}.
-         * @hide
-         */
-        // TODO(sidchhabra): Replace Document with proper constructor.
-        @Nullable
-        public List<MatchInfo> getMatchInfo() {
-            if (!mResultProto.hasSnippet()) {
-                return null;
-            }
-            AppSearchDocument document = getDocument();
-            List<MatchInfo> matchList = new ArrayList<>();
-            for (Iterator entryProtoIterator = mResultProto.getSnippet()
-                    .getEntriesList().iterator(); entryProtoIterator.hasNext(); ) {
-                SnippetProto.EntryProto entry = (SnippetProto.EntryProto) entryProtoIterator.next();
-                for (Iterator snippetMatchProtoIterator = entry.getSnippetMatchesList().iterator();
-                        snippetMatchProtoIterator.hasNext(); ) {
-                    matchList.add(new MatchInfo(entry.getPropertyName(),
-                            (SnippetMatchProto) snippetMatchProtoIterator.next(), document));
-                }
-            }
-            return matchList;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return mSearchResultProto.toString();
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
deleted file mode 100644
index c276ae1..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import com.google.android.icing.proto.ResultSpecProto;
-import com.google.android.icing.proto.ScoringSpecProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-
-/**
- * This class represents the specification logic for AppSearch. It can be used to set the type of
- * search, like prefix or exact only or apply filters to search for a specific schema type only etc.
- * @hide
- */
-// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
-public final class SearchSpec {
-
-    private final SearchSpecProto mSearchSpecProto;
-    private final ResultSpecProto mResultSpecProto;
-    private final ScoringSpecProto mScoringSpecProto;
-
-    private SearchSpec(@NonNull SearchSpecProto searchSpecProto,
-            @NonNull ResultSpecProto resultSpecProto, @NonNull ScoringSpecProto scoringSpecProto) {
-        mSearchSpecProto = searchSpecProto;
-        mResultSpecProto = resultSpecProto;
-        mScoringSpecProto = scoringSpecProto;
-    }
-
-    /** Creates a new {@link SearchSpec.Builder}. */
-    @NonNull
-    public static SearchSpec.Builder newBuilder() {
-        return new SearchSpec.Builder();
-    }
-
-    /** @hide */
-    @NonNull
-    SearchSpecProto getSearchSpecProto() {
-        return mSearchSpecProto;
-    }
-
-    /** @hide */
-    @NonNull
-    ResultSpecProto getResultSpecProto() {
-        return mResultSpecProto;
-    }
-
-    /** @hide */
-    @NonNull
-    ScoringSpecProto getScoringSpecProto() {
-        return mScoringSpecProto;
-    }
-
-    /** Term Match Type for the query. */
-    // NOTE: The integer values of these constants must match the proto enum constants in
-    // {@link com.google.android.icing.proto.SearchSpecProto.termMatchType}
-    @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = {
-            TERM_MATCH_TYPE_EXACT_ONLY,
-            TERM_MATCH_TYPE_PREFIX
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface TermMatchTypeCode {}
-
-    /**
-     * Query terms will only match exact tokens in the index.
-     * <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football".
-     */
-    public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1;
-    /**
-     * Query terms will match indexed tokens when the query term is a prefix of the token.
-     * <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football".
-     */
-    public static final int TERM_MATCH_TYPE_PREFIX = 2;
-
-    /** Ranking Strategy for query result.*/
-    // NOTE: The integer values of these constants must match the proto enum constants in
-    // {@link ScoringSpecProto.RankingStrategy.Code }
-    @IntDef(prefix = {"RANKING_STRATEGY_"}, value = {
-            RANKING_STRATEGY_NONE,
-            RANKING_STRATEGY_DOCUMENT_SCORE,
-            RANKING_STRATEGY_CREATION_TIMESTAMP
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface RankingStrategyCode {}
-
-    /** No Ranking, results are returned in arbitrary order.*/
-    public static final int RANKING_STRATEGY_NONE = 0;
-    /** Ranked by app-provided document scores. */
-    public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1;
-    /** Ranked by document creation timestamps. */
-    public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
-
-    /** Order for query result.*/
-    // NOTE: The integer values of these constants must match the proto enum constants in
-    // {@link ScoringSpecProto.Order.Code }
-    @IntDef(prefix = {"ORDER_"}, value = {
-            ORDER_DESCENDING,
-            ORDER_ASCENDING
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface OrderCode {}
-
-    /** Search results will be returned in a descending order. */
-    public static final int ORDER_DESCENDING = 0;
-    /** Search results will be returned in an ascending order. */
-    public static final int ORDER_ASCENDING = 1;
-
-    /** Builder for {@link SearchSpec objects}. */
-    public static final class Builder {
-
-        private final SearchSpecProto.Builder mSearchSpecBuilder = SearchSpecProto.newBuilder();
-        private final ResultSpecProto.Builder mResultSpecBuilder = ResultSpecProto.newBuilder();
-        private final ScoringSpecProto.Builder mScoringSpecBuilder = ScoringSpecProto.newBuilder();
-        private final ResultSpecProto.SnippetSpecProto.Builder mSnippetSpecBuilder =
-                ResultSpecProto.SnippetSpecProto.newBuilder();
-
-        private Builder() {
-        }
-
-        /**
-         * Indicates how the query terms should match {@link TermMatchTypeCode} in the index.
-         */
-        @NonNull
-        public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) {
-            TermMatchType.Code termMatchTypeCodeProto =
-                    TermMatchType.Code.forNumber(termMatchTypeCode);
-            if (termMatchTypeCodeProto == null) {
-                throw new IllegalArgumentException("Invalid term match type: "
-                        + termMatchTypeCode);
-            }
-            mSearchSpecBuilder.setTermMatchType(termMatchTypeCodeProto);
-            return this;
-        }
-
-        /**
-         * Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that
-         * have the specified schema types.
-         * <p>If unset, the query will search over all schema types.
-         */
-        @NonNull
-        public Builder setSchemaTypes(@NonNull String... schemaTypes) {
-            for (String schemaType : schemaTypes) {
-                mSearchSpecBuilder.addSchemaTypeFilters(schemaType);
-            }
-            return this;
-        }
-
-        /** Sets the maximum number of results to retrieve from the query */
-        @NonNull
-        public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) {
-            mResultSpecBuilder.setNumToRetrieve(numToRetrieve);
-            return this;
-        }
-
-        /** Sets ranking strategy for AppSearch results.*/
-        @NonNull
-        public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) {
-            ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto =
-                    ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategy);
-            if (rankingStrategyCodeProto == null) {
-                throw new IllegalArgumentException("Invalid result ranking strategy: "
-                        + rankingStrategyCodeProto);
-            }
-            mScoringSpecBuilder.setRankBy(rankingStrategyCodeProto);
-            return this;
-        }
-
-        /**
-         * Indicates the order of returned search results, the default is DESC, meaning that results
-         * with higher scores come first.
-         * <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}.
-         */
-        @NonNull
-        public Builder setOrder(@OrderCode int order) {
-            ScoringSpecProto.Order.Code orderCodeProto =
-                    ScoringSpecProto.Order.Code.forNumber(order);
-            if (orderCodeProto == null) {
-                throw new IllegalArgumentException("Invalid result ranking order: "
-                        + orderCodeProto);
-            }
-            mScoringSpecBuilder.setOrderBy(orderCodeProto);
-            return this;
-        }
-
-        /**
-         * Only the first {@code numToSnippet} documents based on the ranking strategy
-         * will have snippet information provided.
-         * <p>If set to 0 (default), snippeting is disabled and
-         * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result.
-         */
-        @NonNull
-        public SearchSpec.Builder setNumToSnippet(int numToSnippet) {
-            mSnippetSpecBuilder.setNumToSnippet(numToSnippet);
-            return this;
-        }
-
-        /**
-         * Only the first {@code numMatchesPerProperty} matches for a every property of
-         * {@link AppSearchDocument} will contain snippet information.
-         * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo}
-         * will return {@code null} for that result.
-         */
-        @NonNull
-        public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) {
-            mSnippetSpecBuilder.setNumMatchesPerProperty(numMatchesPerProperty);
-            return this;
-        }
-
-        /**
-         * Sets {@code maxSnippetSize}, the maximum snippet size. Snippet windows start at
-         * {@code maxSnippetSize/2} bytes before the middle of the matching token and end at
-         * {@code maxSnippetSize/2} bytes after the middle of the matching token. It respects
-         * token boundaries, therefore the returned window may be smaller than requested.
-         * <p> Setting {@code maxSnippetSize} to 0 will disable windowing and an empty string will
-         * be returned. If matches enabled is also set to false, then snippeting is disabled.
-         * <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
-         * return a window of "bar baz bat" which is only 11 bytes long.
-         */
-        @NonNull
-        public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) {
-            mSnippetSpecBuilder.setMaxWindowBytes(maxSnippetSize);
-            return this;
-        }
-
-        /**
-         * Constructs a new {@link SearchSpec} from the contents of this builder.
-         *
-         * <p>After calling this method, the builder must no longer be used.
-         */
-        @NonNull
-        public SearchSpec build() {
-            if (mSearchSpecBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) {
-                throw new IllegalSearchSpecException("Missing termMatchType field.");
-            }
-            mResultSpecBuilder.setSnippetSpec(mSnippetSpecBuilder);
-            return new SearchSpec(mSearchSpecBuilder.build(), mResultSpecBuilder.build(),
-                    mScoringSpecBuilder.build());
-        }
-    }
-}
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
deleted file mode 100644
index 04f385e..0000000
--- a/apex/appsearch/service/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-java_library {
-    name: "service-appsearch",
-    installable: true,
-    srcs: ["java/**/*.java"],
-    libs: [
-        "framework",
-        "framework-appsearch",
-        "services.core",
-    ],
-    apex_available: ["com.android.appsearch"],
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
deleted file mode 100644
index 6293ee7..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch;
-
-import android.annotation.NonNull;
-import android.app.appsearch.AppSearchBatchResult;
-import android.app.appsearch.IAppSearchManager;
-import android.content.Context;
-import android.os.Binder;
-import android.os.UserHandle;
-
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.util.Preconditions;
-import com.android.server.SystemService;
-import com.android.server.appsearch.impl.AppSearchImpl;
-import com.android.server.appsearch.impl.FakeIcing;
-import com.android.server.appsearch.impl.ImplInstanceManager;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.protobuf.InvalidProtocolBufferException;
-
-import java.util.List;
-
-/**
- * TODO(b/142567528): add comments when implement this class
- */
-public class AppSearchManagerService extends SystemService {
-
-    public AppSearchManagerService(Context context) {
-        super(context);
-        mFakeIcing = new FakeIcing();
-    }
-
-    private final FakeIcing mFakeIcing;
-
-    @Override
-    public void onStart() {
-        publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
-    }
-
-    private class Stub extends IAppSearchManager.Stub {
-        @Override
-        public void setSchema(byte[] schemaBytes, boolean forceOverride, AndroidFuture callback) {
-            Preconditions.checkNotNull(schemaBytes);
-            Preconditions.checkNotNull(callback);
-            int callingUid = Binder.getCallingUidOrThrow();
-            int callingUserId = UserHandle.getUserId(callingUid);
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                SchemaProto schema = SchemaProto.parseFrom(schemaBytes);
-                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
-                impl.setSchema(callingUid, schema, forceOverride);
-                callback.complete(null);
-            } catch (Throwable t) {
-                callback.completeExceptionally(t);
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
-            }
-        }
-
-        @Override
-        public void putDocuments(
-                List documentsBytes, AndroidFuture<AppSearchBatchResult> callback) {
-            Preconditions.checkNotNull(documentsBytes);
-            Preconditions.checkNotNull(callback);
-            int callingUid = Binder.getCallingUidOrThrow();
-            int callingUserId = UserHandle.getUserId(callingUid);
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
-                AppSearchBatchResult.Builder<String, Void> resultBuilder =
-                        AppSearchBatchResult.newBuilder();
-                for (int i = 0; i < documentsBytes.size(); i++) {
-                    byte[] documentBytes = (byte[]) documentsBytes.get(i);
-                    DocumentProto document = DocumentProto.parseFrom(documentBytes);
-                    try {
-                        impl.putDocument(callingUid, document);
-                        resultBuilder.setSuccess(document.getUri(), /*value=*/ null);
-                    } catch (Throwable t) {
-                        resultBuilder.setFailure(document.getUri(), t);
-                    }
-                }
-                callback.complete(resultBuilder.build());
-            } catch (Throwable t) {
-                callback.completeExceptionally(t);
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
-            }
-        }
-        // TODO(sidchhabra):Init FakeIcing properly.
-        // TODO(sidchhabra): Do this in a threadpool.
-        @Override
-        public void query(@NonNull byte[] searchSpec, @NonNull byte[] resultSpec,
-                @NonNull byte[] scoringSpec, AndroidFuture callback) {
-            Preconditions.checkNotNull(searchSpec);
-            Preconditions.checkNotNull(resultSpec);
-            Preconditions.checkNotNull(scoringSpec);
-            SearchSpecProto searchSpecProto = null;
-            try {
-                searchSpecProto = SearchSpecProto.parseFrom(searchSpec);
-            } catch (InvalidProtocolBufferException e) {
-                throw new RuntimeException(e);
-            }
-            SearchResultProto searchResults =
-                    mFakeIcing.query(searchSpecProto.getQuery());
-            callback.complete(searchResults.toByteArray());
-        }
-    }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
deleted file mode 100644
index ca5b884..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsAppSearchTestCases"
-    },
-    {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.appsearch"
-        }
-      ]
-    },
-    {
-      "name": "FrameworksCoreTests",
-      "options": [
-        {
-           "include-filter": "android.app.appsearch"
-        }
-      ]
-    }
-  ]
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java
deleted file mode 100644
index 04b4b14..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-
-/**
- * Manages interaction with {@link FakeIcing} and other components to implement AppSearch
- * functionality.
- */
-public final class AppSearchImpl {
-    private final Context mContext;
-    private final @UserIdInt int mUserId;
-    private final FakeIcing mFakeIcing = new FakeIcing();
-
-    AppSearchImpl(@NonNull Context context, @UserIdInt int userId) {
-        mContext = context;
-        mUserId = userId;
-    }
-
-    /**
-     * Updates the AppSearch schema for this app.
-     *
-     * @param callingUid The uid of the app calling AppSearch.
-     * @param origSchema The schema to set for this app.
-     * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
-     *     which do not comply with the new schema will be deleted.
-     */
-    public void setSchema(int callingUid, @NonNull SchemaProto origSchema, boolean forceOverride) {
-        // Rewrite schema type names to include the calling app's package and uid.
-        String typePrefix = getTypePrefix(callingUid);
-        SchemaProto.Builder schemaBuilder = origSchema.toBuilder();
-        rewriteSchemaTypes(typePrefix, schemaBuilder);
-
-        // TODO(b/145635424): Save in schema type map
-        // TODO(b/145635424): Apply the schema to Icing and report results
-    }
-
-    /**
-     * Rewrites all types mentioned in the given {@code schemaBuilder} to prepend
-     * {@code typePrefix}.
-     *
-     * @param typePrefix The prefix to add
-     * @param schemaBuilder The schema to mutate
-     */
-    @VisibleForTesting
-    void rewriteSchemaTypes(
-            @NonNull String typePrefix, @NonNull SchemaProto.Builder schemaBuilder) {
-        for (int typeIdx = 0; typeIdx < schemaBuilder.getTypesCount(); typeIdx++) {
-            SchemaTypeConfigProto.Builder typeConfigBuilder =
-                    schemaBuilder.getTypes(typeIdx).toBuilder();
-
-            // Rewrite SchemaProto.types.schema_type
-            String newSchemaType = typePrefix + typeConfigBuilder.getSchemaType();
-            typeConfigBuilder.setSchemaType(newSchemaType);
-
-            // Rewrite SchemaProto.types.properties.schema_type
-            for (int propertyIdx = 0;
-                    propertyIdx < typeConfigBuilder.getPropertiesCount();
-                    propertyIdx++) {
-                PropertyConfigProto.Builder propertyConfigBuilder =
-                        typeConfigBuilder.getProperties(propertyIdx).toBuilder();
-                if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
-                    String newPropertySchemaType =
-                            typePrefix + propertyConfigBuilder.getSchemaType();
-                    propertyConfigBuilder.setSchemaType(newPropertySchemaType);
-                    typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
-                }
-            }
-
-            schemaBuilder.setTypes(typeIdx, typeConfigBuilder);
-        }
-    }
-
-    /**
-     * Adds a document to the AppSearch index.
-     *
-     * @param callingUid The uid of the app calling AppSearch.
-     * @param origDocument The document to index.
-     */
-    public void putDocument(int callingUid, @NonNull DocumentProto origDocument) {
-        // Rewrite the type names to include the app's prefix
-        String typePrefix = getTypePrefix(callingUid);
-        DocumentProto.Builder documentBuilder = origDocument.toBuilder();
-        rewriteDocumentTypes(typePrefix, documentBuilder);
-        mFakeIcing.put(documentBuilder.build());
-    }
-
-    /**
-     * Rewrites all types mentioned anywhere in {@code documentBuilder} to prepend
-     * {@code typePrefix}.
-     *
-     * @param typePrefix The prefix to add
-     * @param documentBuilder The document to mutate
-     */
-    @VisibleForTesting
-    void rewriteDocumentTypes(
-            @NonNull String typePrefix,
-            @NonNull DocumentProto.Builder documentBuilder) {
-        // Rewrite the type name to include the app's prefix
-        String newSchema = typePrefix + documentBuilder.getSchema();
-        documentBuilder.setSchema(newSchema);
-
-        // Add namespace. If we ever allow users to set their own namespaces, this will have
-        // to change to prepend the prefix instead of setting the whole namespace. We will also have
-        // to store the namespaces in a map similar to the type map so we can rewrite queries with
-        // empty namespaces.
-        documentBuilder.setNamespace(typePrefix);
-
-        // Recurse into derived documents
-        for (int propertyIdx = 0;
-                propertyIdx < documentBuilder.getPropertiesCount();
-                propertyIdx++) {
-            int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
-            if (documentCount > 0) {
-                PropertyProto.Builder propertyBuilder =
-                        documentBuilder.getProperties(propertyIdx).toBuilder();
-                for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
-                    DocumentProto.Builder derivedDocumentBuilder =
-                            propertyBuilder.getDocumentValues(documentIdx).toBuilder();
-                    rewriteDocumentTypes(typePrefix, derivedDocumentBuilder);
-                    propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
-                }
-                documentBuilder.setProperties(propertyIdx, propertyBuilder);
-            }
-        }
-    }
-
-   /**
-     * Returns a type prefix in a format like {@code com.example.package@1000/} or
-     * {@code com.example.sharedname:5678@1000/}.
-     */
-    @NonNull
-    private String getTypePrefix(int callingUid) {
-        // For regular apps, this call will return the package name. If callingUid is an
-        // android:sharedUserId, this value may be another type of name and have a :uid suffix.
-        String callingUidName = mContext.getPackageManager().getNameForUid(callingUid);
-        if (callingUidName == null) {
-            // Not sure how this is possible --- maybe app was uninstalled?
-            throw new IllegalStateException("Failed to look up package name for uid " + callingUid);
-        }
-        return callingUidName + "@" + mUserId + "/";
-    }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
deleted file mode 100644
index d07ef4b..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.StatusProto;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Fake in-memory implementation of the Icing key-value store and reverse index.
- * <p>
- * Currently, only queries by single exact term are supported. There is no support for persistence,
- * namespaces, i18n tokenization, or schema.
- */
-public class FakeIcing {
-    private final AtomicInteger mNextDocId = new AtomicInteger();
-    private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>();
-    /** Array of Documents where index into the array is the docId. */
-    private final SparseArray<DocumentProto> mDocStore = new SparseArray<>();
-    /** Map of term to posting-list (the set of DocIds containing that term). */
-    private final Map<String, Set<Integer>> mIndex = new ArrayMap<>();
-
-    /**
-     * Inserts a document into the index.
-     *
-     * @param document The document to insert.
-     */
-    public void put(@NonNull DocumentProto document) {
-        String uri = document.getUri();
-
-        // Update mDocIdMap
-        Integer docId = mUriToDocIdMap.get(uri);
-        if (docId != null) {
-            // Delete the old doc
-            mDocStore.remove(docId);
-        }
-
-        // Allocate a new docId
-        docId = mNextDocId.getAndIncrement();
-        mUriToDocIdMap.put(uri, docId);
-
-        // Update mDocStore
-        mDocStore.put(docId, document);
-
-        // Update mIndex
-        indexDocument(docId, document);
-    }
-
-    /**
-     * Retrieves a document from the index.
-     *
-     * @param uri The URI of the document to retrieve.
-     * @return The body of the document, or {@code null} if no such document exists.
-     */
-    @Nullable
-    public DocumentProto get(@NonNull String uri) {
-        Integer docId = mUriToDocIdMap.get(uri);
-        if (docId == null) {
-            return null;
-        }
-        return mDocStore.get(docId);
-    }
-
-    /**
-     * Returns documents containing the given term.
-     *
-     * @param term A single exact term to look up in the index.
-     * @return A {@link SearchResultProto} containing the matching documents, which may have no
-     *   results if no documents match.
-     */
-    @NonNull
-    public SearchResultProto query(@NonNull String term) {
-        String normTerm = normalizeString(term);
-        Set<Integer> docIds = mIndex.get(normTerm);
-        SearchResultProto.Builder results = SearchResultProto.newBuilder()
-                .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK));
-        if (docIds == null || docIds.isEmpty()) {
-            return results.build();
-        }
-
-        for (int docId : docIds) {
-            DocumentProto document = mDocStore.get(docId);
-            if (document != null) {
-                results.addResults(
-                        SearchResultProto.ResultProto.newBuilder().setDocument(document));
-            }
-        }
-        return results.build();
-    }
-
-    /**
-     * Deletes a document by its URI.
-     *
-     * @param uri The URI of the document to be deleted.
-     */
-    public void delete(@NonNull String uri) {
-        // Update mDocIdMap
-        Integer docId = mUriToDocIdMap.get(uri);
-        if (docId != null) {
-            // Delete the old doc
-            mDocStore.remove(docId);
-            mUriToDocIdMap.remove(uri);
-        }
-    }
-
-    private void indexDocument(int docId, DocumentProto document) {
-        for (PropertyProto property : document.getPropertiesList()) {
-            for (String stringValue : property.getStringValuesList()) {
-                String[] words = normalizeString(stringValue).split("\\s+");
-                for (String word : words) {
-                    indexTerm(docId, word);
-                }
-            }
-            for (Long longValue : property.getInt64ValuesList()) {
-                indexTerm(docId, longValue.toString());
-            }
-            for (Double doubleValue : property.getDoubleValuesList()) {
-                indexTerm(docId, doubleValue.toString());
-            }
-            for (Boolean booleanValue : property.getBooleanValuesList()) {
-                indexTerm(docId, booleanValue.toString());
-            }
-            // Intentionally skipping bytes values
-            for (DocumentProto documentValue : property.getDocumentValuesList()) {
-                indexDocument(docId, documentValue);
-            }
-        }
-    }
-
-    private void indexTerm(int docId, String term) {
-        Set<Integer> postingList = mIndex.get(term);
-        if (postingList == null) {
-            postingList = new ArraySet<>();
-            mIndex.put(term, postingList);
-        }
-        postingList.add(docId);
-    }
-
-    /** Strips out punctuation and converts to lowercase. */
-    private static String normalizeString(String input) {
-        return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault());
-    }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java
deleted file mode 100644
index 395e30e..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.util.SparseArray;
-
-/**
- * Manages the lifecycle of instances of {@link AppSearchImpl}.
- *
- * <p>These instances are managed per unique device-user.
- */
-public final class ImplInstanceManager {
-    private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>();
-
-    /**
-     * Gets an instance of AppSearchImpl for the given user.
-     *
-     * <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will
-     * be created.
-     *
-     * @param context The Android context
-     * @param userId The multi-user userId of the device user calling AppSearch
-     * @return An initialized {@link AppSearchImpl} for this user
-     */
-    @NonNull
-    public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId) {
-        AppSearchImpl instance = sInstances.get(userId);
-        if (instance == null) {
-            synchronized (ImplInstanceManager.class) {
-                instance = sInstances.get(userId);
-                if (instance == null) {
-                    instance = new AppSearchImpl(context, userId);
-                    sInstances.put(userId, instance);
-                }
-            }
-        }
-        return instance;
-    }
-}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 05c6611..49adaa8 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -939,6 +939,12 @@
         }
     }
 
+    void runIdleMaintenance() {
+        synchronized (mBlobsLock) {
+            handleIdleMaintenanceLocked();
+        }
+    }
+
     @GuardedBy("mBlobsLock")
     private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
         for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
@@ -1408,9 +1414,7 @@
     private class LocalService extends BlobStoreManagerInternal {
         @Override
         public void onIdleMaintenance() {
-            synchronized (mBlobsLock) {
-                handleIdleMaintenanceLocked();
-            }
+            runIdleMaintenance();
         }
     }
 
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
index d58294b..72af323 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
@@ -44,6 +44,8 @@
                 return runClearAllBlobs(pw);
             case "delete-blob":
                 return runDeleteBlob(pw);
+            case "idle-maintenance":
+                return runIdleMaintenance(pw);
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -84,6 +86,11 @@
         return 0;
     }
 
+    private int runIdleMaintenance(PrintWriter pw) {
+        mService.runIdleMaintenance();
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
@@ -112,6 +119,8 @@
         pw.println("      --expiry: Expiry time of the blob to delete, in milliseconds.");
         pw.println("      --label: Label of the blob to delete.");
         pw.println("      --tag: Tag of the blob to delete.");
+        pw.println("idle-maintenance");
+        pw.println("    Run idle maintenance which takes care of removing stale data.");
         pw.println();
     }
 
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index cc4044e..62701e5 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -347,12 +347,12 @@
 
     @Override
     public void close() {
-        closeSession(STATE_CLOSED);
+        closeSession(STATE_CLOSED, false /* sendCallback */);
     }
 
     @Override
     public void abandon() {
-        closeSession(STATE_ABANDONED);
+        closeSession(STATE_ABANDONED, true /* sendCallback */);
     }
 
     @Override
@@ -360,11 +360,11 @@
         synchronized (mSessionLock) {
             mBlobCommitCallback = callback;
 
-            closeSession(STATE_COMMITTED);
+            closeSession(STATE_COMMITTED, true /* sendCallback */);
         }
     }
 
-    private void closeSession(int state) {
+    private void closeSession(int state, boolean sendCallback) {
         assertCallerIsOwner();
         synchronized (mSessionLock) {
             if (mState != STATE_OPENED) {
@@ -381,7 +381,9 @@
             mState = state;
             revokeAllFdsLocked();
 
-            mListener.onStateChanged(this);
+            if (sendCallback) {
+                mListener.onStateChanged(this);
+            }
         }
     }
 
@@ -457,6 +459,10 @@
                 return "<abandoned>";
             case STATE_COMMITTED:
                 return "<committed>";
+            case STATE_VERIFIED_VALID:
+                return "<verified_valid>";
+            case STATE_VERIFIED_INVALID:
+                return "<verified_invalid>";
             default:
                 Slog.wtf(TAG, "Unknown state: " + state);
                 return "<unknown>";
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index cdcd6598..e2e1180 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -1,6 +1,13 @@
 {
     "presubmit": [
         {
+            "name": "CtsJobSchedulerTestCases",
+            "options": [
+                {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+                {"exclude-annotation": "androidx.test.filters.LargeTest"}
+            ]
+        },
+        {
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {"include-filter": "com.android.server.job"},
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
index 4a259f5..b59a97e 100644
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -128,7 +128,7 @@
     void removeConfiguration(in long configId, in String packageName);
 
     /** Tell StatsManagerService to register a puller for the given atom tag with statsd. */
-    oneway void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+    oneway void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
             in int[] additiveFields, IPullAtomCallback pullerCallback);
 
     /** Tell StatsManagerService to unregister the pulller for the given atom tag from statsd. */
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 10b1e5b..c8aec53 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -186,8 +186,9 @@
     * Registers a puller callback function that, when invoked, pulls the data
     * for the specified atom tag.
     */
-    oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownNs, long timeoutNs,
-                           in int[] additiveFields, IPullAtomCallback pullerCallback);
+    oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownMillis,
+                                         long timeoutMillis,in int[] additiveFields,
+                                         IPullAtomCallback pullerCallback);
 
    /**
     * Registers a puller callback function that, when invoked, pulls the data
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 1bd770a..8185bb0 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -43,6 +43,7 @@
     ],
     visibility: [
         "//frameworks/base", // For the "global" stubs.
+        "//frameworks/base/apex/statsd:__subpackages__",
     ],
 }
 
@@ -74,8 +75,6 @@
     hostdex: true, // for hiddenapi check
     visibility: [
         "//frameworks/base/apex/statsd:__subpackages__",
-        // TODO(b/149928788): Remove when tests are moved.
-        "//frameworks/base/core/tests/coretests:__pkg__",
     ],
     apex_available: [
         "com.android.os.statsd",
@@ -164,3 +163,26 @@
         "//frameworks/opt/net/wifi/service" // wifi service
     ]
 }
+
+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",
+    ],
+}
+
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index e637187..f021dcf 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -119,14 +119,12 @@
     /**
      * @hide
      **/
-    @VisibleForTesting
-    public static final long DEFAULT_COOL_DOWN_NS = 1_000_000_000L; // 1 second.
+    @VisibleForTesting public static final long DEFAULT_COOL_DOWN_MILLIS = 1_000L; // 1 second.
 
     /**
      * @hide
      **/
-    @VisibleForTesting
-    public static final long DEFAULT_TIMEOUT_NS = 10_000_000_000L; // 10 seconds.
+    @VisibleForTesting public static final long DEFAULT_TIMEOUT_MILLIS = 10_000L; // 10 seconds.
 
     /**
      * Constructor for StatsManagerClient.
@@ -489,23 +487,24 @@
     }
 
     /**
-     * Registers a callback for an atom when that atom is to be pulled. The stats service will
+     * Sets a callback for an atom when that atom is to be pulled. The stats service will
      * invoke pullData in the callback when the stats service determines that this atom needs to be
      * pulled. This method should not be called by third-party apps.
      *
      * @param atomTag           The tag of the atom for this puller callback.
      * @param metadata          Optional metadata specifying the timeout, cool down time, and
      *                          additive fields for mapping isolated to host uids.
-     * @param callback          The callback to be invoked when the stats service pulls the atom.
      * @param executor          The executor in which to run the callback.
+     * @param callback          The callback to be invoked when the stats service pulls the atom.
      *
      */
     @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
-    public void registerPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
+    public void setPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull StatsPullAtomCallback callback) {
-        long coolDownNs = metadata == null ? DEFAULT_COOL_DOWN_NS : metadata.mCoolDownNs;
-        long timeoutNs = metadata == null ? DEFAULT_TIMEOUT_NS : metadata.mTimeoutNs;
+        long coolDownMillis =
+                metadata == null ? DEFAULT_COOL_DOWN_MILLIS : metadata.mCoolDownMillis;
+        long timeoutMillis = metadata == null ? DEFAULT_TIMEOUT_MILLIS : metadata.mTimeoutMillis;
         int[] additiveFields = metadata == null ? new int[0] : metadata.mAdditiveFields;
         if (additiveFields == null) {
             additiveFields = new int[0];
@@ -516,8 +515,8 @@
                 IStatsManagerService service = getIStatsManagerServiceLocked();
                 PullAtomCallbackInternal rec =
                     new PullAtomCallbackInternal(atomTag, callback, executor);
-                service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields,
-                        rec);
+                service.registerPullAtomCallback(
+                        atomTag, coolDownMillis, timeoutMillis, additiveFields, rec);
             } catch (RemoteException e) {
                 throw new RuntimeException("Unable to register pull callback", e);
             }
@@ -525,14 +524,14 @@
     }
 
     /**
-     * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
+     * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
      * pulls will still occur. This method should not be called by third-party apps.
      *
      * @param atomTag           The tag of the atom of which to unregister
      *
      */
     @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
-    public void unregisterPullAtomCallback(int atomTag) {
+    public void clearPullAtomCallback(int atomTag) {
         synchronized (sLock) {
             try {
                 IStatsManagerService service = getIStatsManagerServiceLocked();
@@ -585,14 +584,14 @@
      *
      */
     public static class PullAtomMetadata {
-        private final long mCoolDownNs;
-        private final long mTimeoutNs;
+        private final long mCoolDownMillis;
+        private final long mTimeoutMillis;
         private final int[] mAdditiveFields;
 
         // Private Constructor for builder
-        private PullAtomMetadata(long coolDownNs, long timeoutNs, int[] additiveFields) {
-            mCoolDownNs = coolDownNs;
-            mTimeoutNs = timeoutNs;
+        private PullAtomMetadata(long coolDownMillis, long timeoutMillis, int[] additiveFields) {
+            mCoolDownMillis = coolDownMillis;
+            mTimeoutMillis = timeoutMillis;
             mAdditiveFields = additiveFields;
         }
 
@@ -600,8 +599,8 @@
          *  Builder for PullAtomMetadata.
          */
         public static class Builder {
-            private long mCoolDownNs;
-            private long mTimeoutNs;
+            private long mCoolDownMillis;
+            private long mTimeoutMillis;
             private int[] mAdditiveFields;
 
             /**
@@ -609,27 +608,28 @@
              * StatsManager#registerPullAtomCallback
              */
             public Builder() {
-                mCoolDownNs = DEFAULT_COOL_DOWN_NS;
-                mTimeoutNs = DEFAULT_TIMEOUT_NS;
+                mCoolDownMillis = DEFAULT_COOL_DOWN_MILLIS;
+                mTimeoutMillis = DEFAULT_TIMEOUT_MILLIS;
                 mAdditiveFields = null;
             }
 
             /**
-             * Set the cool down time of the pull in nanoseconds. If two successive pulls are issued
-             * within the cool down, a cached version of the first will be used for the second.
+             * Set the cool down time of the pull in milliseconds. If two successive pulls are
+             * issued within the cool down, a cached version of the first pull will be used for the
+             * second pull.
              */
             @NonNull
-            public Builder setCoolDownNs(long coolDownNs) {
-                mCoolDownNs = coolDownNs;
+            public Builder setCoolDownMillis(long coolDownMillis) {
+                mCoolDownMillis = coolDownMillis;
                 return this;
             }
 
             /**
-             * Set the maximum time the pull can take in nanoseconds.
+             * Set the maximum time the pull can take in milliseconds.
              */
             @NonNull
-            public Builder setTimeoutNs(long timeoutNs) {
-                mTimeoutNs = timeoutNs;
+            public Builder setTimeoutMillis(long timeoutMillis) {
+                mTimeoutMillis = timeoutMillis;
                 return this;
             }
 
@@ -652,30 +652,32 @@
              */
             @NonNull
             public PullAtomMetadata build() {
-                return new PullAtomMetadata(mCoolDownNs, mTimeoutNs, mAdditiveFields);
+                return new PullAtomMetadata(mCoolDownMillis, mTimeoutMillis, mAdditiveFields);
             }
         }
 
         /**
-         * @hide
+         * Return the cool down time of this pull in milliseconds.
          */
-        @VisibleForTesting
-        public long getCoolDownNs() {
-            return mCoolDownNs;
+        public long getCoolDownMillis() {
+            return mCoolDownMillis;
         }
 
         /**
-         * @hide
+         * Return the maximum amount of time this pull can take in milliseconds.
          */
-        @VisibleForTesting
-        public long getTimeoutNs() {
-            return mTimeoutNs;
+        public long getTimeoutMillis() {
+            return mTimeoutMillis;
         }
 
         /**
-         * @hide
+         * Return the additive fields of this pulled atom.
+         *
+         * This is only applicable for atoms that have a uid field. When tasks are run in
+         * isolated processes, the data will be attributed to the host uid. Additive fields
+         * will be combined when the non-additive fields are the same.
          */
-        @VisibleForTesting
+        @Nullable
         public int[] getAdditiveFields() {
             return mAdditiveFields;
         }
diff --git a/apex/statsd/framework/test/AndroidManifest.xml b/apex/statsd/framework/test/AndroidManifest.xml
new file mode 100644
index 0000000..8f89d23
--- /dev/null
+++ b/apex/statsd/framework/test/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.os.statsd.framework.test"
+        >
+
+    <instrumentation
+            android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.os.statsd.framework.test"
+            android:label="Framework Statsd Tests" />
+
+</manifest>
diff --git a/apex/statsd/framework/test/TEST_MAPPING b/apex/statsd/framework/test/TEST_MAPPING
new file mode 100644
index 0000000..f387958
--- /dev/null
+++ b/apex/statsd/framework/test/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit" : [
+    {
+      "name" : "FrameworkStatsdTest"
+    }
+  ]
+}
diff --git a/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
new file mode 100644
index 0000000..fd386bd
--- /dev/null
+++ b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.StatsManager.PullAtomMetadata;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class PullAtomMetadataTest {
+
+    @Test
+    public void testEmpty() {
+        PullAtomMetadata metadata = new PullAtomMetadata.Builder().build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
+        assertThat(metadata.getAdditiveFields()).isNull();
+    }
+
+    @Test
+    public void testSetTimeoutMillis() {
+        long timeoutMillis = 500L;
+        PullAtomMetadata metadata =
+                new PullAtomMetadata.Builder().setTimeoutMillis(timeoutMillis).build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
+        assertThat(metadata.getAdditiveFields()).isNull();
+    }
+
+    @Test
+    public void testSetCoolDownMillis() {
+        long coolDownMillis = 10_000L;
+        PullAtomMetadata metadata =
+                new PullAtomMetadata.Builder().setCoolDownMillis(coolDownMillis).build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
+        assertThat(metadata.getAdditiveFields()).isNull();
+    }
+
+    @Test
+    public void testSetAdditiveFields() {
+        int[] fields = {2, 4, 6};
+        PullAtomMetadata metadata =
+                new PullAtomMetadata.Builder().setAdditiveFields(fields).build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
+        assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
+    }
+
+    @Test
+    public void testSetAllElements() {
+        long timeoutMillis = 300L;
+        long coolDownMillis = 9572L;
+        int[] fields = {3, 2};
+        PullAtomMetadata metadata = new PullAtomMetadata.Builder()
+                .setTimeoutMillis(timeoutMillis)
+                .setCoolDownMillis(coolDownMillis)
+                .setAdditiveFields(fields)
+                .build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
+        assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
+    }
+}
diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
similarity index 100%
rename from core/tests/coretests/src/android/util/StatsEventTest.java
rename to apex/statsd/framework/test/src/android/util/StatsEventTest.java
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 4e4bc40..58c78da 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -136,25 +136,25 @@
     }
 
     private static class PullerValue {
-        private final long mCoolDownNs;
-        private final long mTimeoutNs;
+        private final long mCoolDownMillis;
+        private final long mTimeoutMillis;
         private final int[] mAdditiveFields;
         private final IPullAtomCallback mCallback;
 
-        PullerValue(long coolDownNs, long timeoutNs, int[] additiveFields,
+        PullerValue(long coolDownMillis, long timeoutMillis, int[] additiveFields,
                 IPullAtomCallback callback) {
-            mCoolDownNs = coolDownNs;
-            mTimeoutNs = timeoutNs;
+            mCoolDownMillis = coolDownMillis;
+            mTimeoutMillis = timeoutMillis;
             mAdditiveFields = additiveFields;
             mCallback = callback;
         }
 
-        public long getCoolDownNs() {
-            return mCoolDownNs;
+        public long getCoolDownMillis() {
+            return mCoolDownMillis;
         }
 
-        public long getTimeoutNs() {
-            return mTimeoutNs;
+        public long getTimeoutMillis() {
+            return mTimeoutMillis;
         }
 
         public int[] getAdditiveFields() {
@@ -169,12 +169,13 @@
     private final ArrayMap<PullerKey, PullerValue> mPullers = new ArrayMap<>();
 
     @Override
-    public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+    public void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
             int[] additiveFields, IPullAtomCallback pullerCallback) {
         enforceRegisterStatsPullAtomPermission();
         int callingUid = Binder.getCallingUid();
         PullerKey key = new PullerKey(callingUid, atomTag);
-        PullerValue val = new PullerValue(coolDownNs, timeoutNs, additiveFields, pullerCallback);
+        PullerValue val =
+                new PullerValue(coolDownMillis, timeoutMillis, additiveFields, pullerCallback);
 
         // Always cache the puller in StatsManagerService. If statsd is down, we will register the
         // puller when statsd comes back up.
@@ -189,8 +190,8 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            statsd.registerPullAtomCallback(
-                    callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
+            statsd.registerPullAtomCallback(callingUid, atomTag, coolDownMillis, timeoutMillis,
+                    additiveFields, pullerCallback);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
         } finally {
@@ -596,8 +597,8 @@
         for (Map.Entry<PullerKey, PullerValue> entry : pullersCopy.entrySet()) {
             PullerKey key = entry.getKey();
             PullerValue value = entry.getValue();
-            statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownNs(),
-                    value.getTimeoutNs(), value.getAdditiveFields(), value.getCallback());
+            statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownMillis(),
+                    value.getTimeoutMillis(), value.getAdditiveFields(), value.getCallback());
         }
     }
 
diff --git a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
index eb97f65..9e5aa95 100644
--- a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
+++ b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <android/binder_process.h>
 #include <jni.h>
 #include <log/log.h>
 #include <stats_event.h>
@@ -32,17 +31,6 @@
 static int32_t sAtomsPerPull;
 static int32_t sNumPulls = 0;
 
-static bool initialized = false;
-
-static void init() {
-    if (!initialized) {
-        initialized = true;
-        // Set up the binder
-        ABinderProcess_setThreadPoolMaxThreadCount(9);
-        ABinderProcess_startThreadPool();
-    }
-}
-
 static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag, AStatsEventList* data,
                                                              void* /*cookie*/) {
     sNumPulls++;
@@ -62,7 +50,6 @@
         JNIEnv* /*env*/, jobject /* this */, jint atomTag, jlong timeoutNs, jlong coolDownNs,
         jint pullRetVal, jlong latencyMillis, int atomsPerPull)
 {
-    init();
     sAtomTag = atomTag;
     sPullReturnVal = pullRetVal;
     sLatencyMillis = latencyMillis;
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
index e119b4c..d4e51e0 100644
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
+++ b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
@@ -229,7 +229,7 @@
         // Let the current bucket finish.
         Thread.sleep(LONG_SLEEP_MILLIS);
         List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        statsManager.unregisterPullAtomCallback(PULL_ATOM_TAG);
+        unregisterStatsPuller(PULL_ATOM_TAG);
         assertThat(data.size()).isEqualTo(sAtomsPerPull);
 
         for (int i = 0; i < data.size(); i++) {
diff --git a/api/current.txt b/api/current.txt
index e9cb9ee..febc7b8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4572,14 +4572,17 @@
     field public static final int REASON_ANR = 6; // 0x6
     field public static final int REASON_CRASH = 4; // 0x4
     field public static final int REASON_CRASH_NATIVE = 5; // 0x5
+    field public static final int REASON_DEPENDENCY_DIED = 12; // 0xc
     field public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; // 0x9
     field public static final int REASON_EXIT_SELF = 1; // 0x1
     field public static final int REASON_INITIALIZATION_FAILURE = 7; // 0x7
     field public static final int REASON_LOW_MEMORY = 3; // 0x3
-    field public static final int REASON_OTHER = 10; // 0xa
+    field public static final int REASON_OTHER = 13; // 0xd
     field public static final int REASON_PERMISSION_CHANGE = 8; // 0x8
     field public static final int REASON_SIGNALED = 2; // 0x2
     field public static final int REASON_UNKNOWN = 0; // 0x0
+    field public static final int REASON_USER_REQUESTED = 10; // 0xa
+    field public static final int REASON_USER_STOPPED = 11; // 0xb
   }
 
   public final class AsyncNotedAppOp implements android.os.Parcelable {
@@ -9921,8 +9924,11 @@
     field public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
     field public static final String EXTRA_SIZE = "android.content.extra.SIZE";
     field public static final String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
+    field public static final int NOTIFY_DELETE = 16; // 0x10
+    field public static final int NOTIFY_INSERT = 4; // 0x4
     field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
     field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
+    field public static final int NOTIFY_UPDATE = 8; // 0x8
     field public static final String QUERY_ARG_GROUP_COLUMNS = "android:query-arg-group-columns";
     field public static final String QUERY_ARG_LIMIT = "android:query-arg-limit";
     field public static final String QUERY_ARG_OFFSET = "android:query-arg-offset";
@@ -12964,9 +12970,13 @@
     ctor public ContentObserver(android.os.Handler);
     method public boolean deliverSelfNotifications();
     method @Deprecated public final void dispatchChange(boolean);
-    method public final void dispatchChange(boolean, android.net.Uri);
+    method public final void dispatchChange(boolean, @Nullable android.net.Uri);
+    method public final void dispatchChange(boolean, @Nullable android.net.Uri, int);
+    method public final void dispatchChange(boolean, @NonNull Iterable<android.net.Uri>, int);
     method public void onChange(boolean);
-    method public void onChange(boolean, android.net.Uri);
+    method public void onChange(boolean, @Nullable android.net.Uri);
+    method public void onChange(boolean, @Nullable android.net.Uri, int);
+    method public void onChange(boolean, @NonNull Iterable<android.net.Uri>, int);
   }
 
   public interface CrossProcessCursor extends android.database.Cursor {
@@ -26899,7 +26909,6 @@
     method public final void notifyRequestFailed(long, int);
     method public final void notifyRoutes(@NonNull java.util.Collection<android.media.MediaRoute2Info>);
     method public final void notifySessionCreated(@NonNull android.media.RoutingSessionInfo, long);
-    method public final void notifySessionCreationFailed(long);
     method public final void notifySessionReleased(@NonNull String);
     method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
     method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -42784,7 +42793,7 @@
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
-    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationParameters(@IntRange(from=0xffffffff) int, int);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationParameters(@IntRange(from=0) int, int);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int);
@@ -42902,7 +42911,7 @@
     method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
-    method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationParameters(@IntRange(from=0xffffffff) int, int);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationParameters(@IntRange(from=0) int, int);
     method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
     method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method @Deprecated @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int);
@@ -43504,6 +43513,7 @@
     field public static final int TYPE_RADIATOR = 16; // 0x10
     field public static final int TYPE_REFRIGERATOR = 48; // 0x30
     field public static final int TYPE_REMOTE_CONTROL = 17; // 0x11
+    field public static final int TYPE_ROUTINE = 52; // 0x34
     field public static final int TYPE_SECURITY_SYSTEM = 46; // 0x2e
     field public static final int TYPE_SET_TOP = 18; // 0x12
     field public static final int TYPE_SHOWER = 29; // 0x1d
@@ -43542,9 +43552,9 @@
   public abstract class ControlAction {
     method public abstract int getActionType();
     method @Nullable public String getChallengeValue();
+    method @NonNull public static android.service.controls.actions.ControlAction getErrorAction();
     method @NonNull public String getTemplateId();
     method public static final boolean isValidResponse(int);
-    field @NonNull public static final android.service.controls.actions.ControlAction ERROR_ACTION;
     field public static final int RESPONSE_CHALLENGE_ACK = 3; // 0x3
     field public static final int RESPONSE_CHALLENGE_PASSPHRASE = 5; // 0x5
     field public static final int RESPONSE_CHALLENGE_PIN = 4; // 0x4
@@ -43556,7 +43566,6 @@
     field public static final int TYPE_ERROR = -1; // 0xffffffff
     field public static final int TYPE_FLOAT = 2; // 0x2
     field public static final int TYPE_MODE = 4; // 0x4
-    field public static final int TYPE_MULTI_FLOAT = 3; // 0x3
   }
 
   public final class FloatAction extends android.service.controls.actions.ControlAction {
@@ -43573,13 +43582,6 @@
     method public int getNewMode();
   }
 
-  public final class MultiFloatAction extends android.service.controls.actions.ControlAction {
-    ctor public MultiFloatAction(@NonNull String, @NonNull float[], @Nullable String);
-    ctor public MultiFloatAction(@NonNull String, @NonNull float[]);
-    method public int getActionType();
-    method @NonNull public float[] getNewValues();
-  }
-
 }
 
 package android.service.controls.templates {
@@ -43594,16 +43596,15 @@
   }
 
   public abstract class ControlTemplate {
+    method @NonNull public static android.service.controls.templates.ControlTemplate getErrorTemplate();
+    method @NonNull public static android.service.controls.templates.ControlTemplate getNoTemplateObject();
     method @NonNull public String getTemplateId();
     method public abstract int getTemplateType();
-    field @NonNull public static final android.service.controls.templates.ControlTemplate ERROR_TEMPLATE;
-    field @NonNull public static final android.service.controls.templates.ControlTemplate NO_TEMPLATE;
     field public static final int TYPE_ERROR = -1; // 0xffffffff
-    field public static final int TYPE_NONE = 0; // 0x0
+    field public static final int TYPE_NO_TEMPLATE = 0; // 0x0
     field public static final int TYPE_RANGE = 2; // 0x2
     field public static final int TYPE_STATELESS = 8; // 0x8
     field public static final int TYPE_TEMPERATURE = 7; // 0x7
-    field public static final int TYPE_THUMBNAIL = 3; // 0x3
     field public static final int TYPE_TOGGLE = 1; // 0x1
     field public static final int TYPE_TOGGLE_RANGE = 6; // 0x6
   }
@@ -43643,13 +43644,6 @@
     field public static final int MODE_UNKNOWN = 0; // 0x0
   }
 
-  public final class ThumbnailTemplate extends android.service.controls.templates.ControlTemplate {
-    ctor public ThumbnailTemplate(@NonNull String, @NonNull android.graphics.drawable.Icon, @NonNull CharSequence);
-    method @NonNull public CharSequence getContentDescription();
-    method public int getTemplateType();
-    method @NonNull public android.graphics.drawable.Icon getThumbnail();
-  }
-
   public final class ToggleRangeTemplate extends android.service.controls.templates.ControlTemplate {
     ctor public ToggleRangeTemplate(@NonNull String, @NonNull android.service.controls.templates.ControlButton, @NonNull android.service.controls.templates.RangeTemplate);
     ctor public ToggleRangeTemplate(@NonNull String, boolean, @NonNull CharSequence, @NonNull android.service.controls.templates.RangeTemplate);
@@ -48305,10 +48299,6 @@
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
     field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
     field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
-    field public static final int MODEM_COUNT_DUAL_MODEM = 2; // 0x2
-    field public static final int MODEM_COUNT_NO_MODEM = 0; // 0x0
-    field public static final int MODEM_COUNT_SINGLE_MODEM = 1; // 0x1
-    field public static final int MODEM_COUNT_TRI_MODEM = 3; // 0x3
     field public static final int MULTISIM_ALLOWED = 0; // 0x0
     field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2
     field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index 1098e3f..f062112 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -702,12 +702,12 @@
   public final class StatsManager {
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]);
+    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void clearPullAtomCallback(int);
     method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getData(long);
     method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getMetadata();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void registerPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
     method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
@@ -715,7 +715,7 @@
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void unregisterPullAtomCallback(int);
+    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void setPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
     field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
     field public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS = "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
     field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
@@ -729,14 +729,17 @@
   }
 
   public static class StatsManager.PullAtomMetadata {
+    method @Nullable public int[] getAdditiveFields();
+    method public long getCoolDownMillis();
+    method public long getTimeoutMillis();
   }
 
   public static class StatsManager.PullAtomMetadata.Builder {
     ctor public StatsManager.PullAtomMetadata.Builder();
     method @NonNull public android.app.StatsManager.PullAtomMetadata build();
     method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setAdditiveFields(@NonNull int[]);
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownNs(long);
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutNs(long);
+    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownMillis(long);
+    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutMillis(long);
   }
 
   public static interface StatsManager.StatsPullAtomCallback {
@@ -921,14 +924,6 @@
 
 }
 
-package android.app.appsearch {
-
-  public class AppSearchManagerFrameworkInitializer {
-    method public static void initialize();
-  }
-
-}
-
 package android.app.assist {
 
   public static class AssistStructure.ViewNode {
@@ -1469,16 +1464,16 @@
 package android.bluetooth {
 
   public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void disableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void enableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void disableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void enableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
     method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothDevice getActiveDevice();
-    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@Nullable android.bluetooth.BluetoothDevice);
+    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int getOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setCodecConfigPreference(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothCodecConfig);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int isOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int isOptionalCodecsSupported(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setCodecConfigPreference(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothCodecConfig);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice, int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int supportsOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice, int);
     field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0
     field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0
     field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1
@@ -5000,6 +4995,11 @@
     field public static final int LENGTH_TYPE_UNDEFINED = 0; // 0x0
     field public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER = 1; // 0x1
     field public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER = 2; // 0x2
+    field public static final int PACKET_TYPE_COMPRESSED = 2; // 0x2
+    field public static final int PACKET_TYPE_EXTENSION = 6; // 0x6
+    field public static final int PACKET_TYPE_IPV4 = 0; // 0x0
+    field public static final int PACKET_TYPE_MPEG2_TS = 7; // 0x7
+    field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
   }
 
   public static class AlpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.AlpFilterConfiguration.Builder> {
@@ -5080,6 +5080,7 @@
     field public static final int TYPE_MMTP = 2; // 0x2
     field public static final int TYPE_TLV = 8; // 0x8
     field public static final int TYPE_TS = 1; // 0x1
+    field public static final int TYPE_UNDEFINED = 0; // 0x0
   }
 
   public interface FilterCallback {
@@ -5090,9 +5091,6 @@
   public abstract class FilterConfiguration {
     method @Nullable public android.media.tv.tuner.filter.Settings getSettings();
     method public abstract int getType();
-    field public static final int PACKET_TYPE_COMPRESSED = 2; // 0x2
-    field public static final int PACKET_TYPE_IPV4 = 0; // 0x0
-    field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
   }
 
   public abstract static class FilterConfiguration.Builder<T extends android.media.tv.tuner.filter.FilterConfiguration.Builder<T>> {
@@ -5290,6 +5288,11 @@
     method public int getType();
     method public boolean isCompressedIpPacket();
     method public boolean isPassthrough();
+    field public static final int PACKET_TYPE_COMPRESSED = 3; // 0x3
+    field public static final int PACKET_TYPE_IPV4 = 1; // 0x1
+    field public static final int PACKET_TYPE_IPV6 = 2; // 0x2
+    field public static final int PACKET_TYPE_NULL = 255; // 0xff
+    field public static final int PACKET_TYPE_SIGNALING = 254; // 0xfe
   }
 
   public static class TlvFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TlvFilterConfiguration.Builder> {
@@ -8140,8 +8143,8 @@
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(int);
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(int);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
@@ -11666,7 +11669,6 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
-    method public boolean isCurrentSimOperator(@NonNull String, int, @Nullable String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataAllowedInVoiceCall();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionEnabled();
     method public boolean isDataConnectivityPossible();
@@ -11685,6 +11687,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
     method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index d6c6c39..6e0bd06 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -231,6 +231,7 @@
     fprintf(out, "  -l           list available sections\n");
     fprintf(out, "  -p           privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
     fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
+    fprintf(out, "  -z           gzip the incident report, i.e. pipe the output through gzip.\n");
     fprintf(out, "\n");
     fprintf(out, "and one of these destinations:\n");
     fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
@@ -255,7 +256,7 @@
 
     // Parse the args
     int opt;
-    while ((opt = getopt(argc, argv, "bhdlp:r:s:u")) != -1) {
+    while ((opt = getopt(argc, argv, "bhdlp:r:s:uz")) != -1) {
         switch (opt) {
             case 'h':
                 usage(stdout);
@@ -302,6 +303,9 @@
                 destination = DEST_BROADCAST;
                 receiverArg = optarg;
                 break;
+            case 'z':
+                args.setGzip(true);
+                break;
             default:
                 usage(stderr);
                 return 1;
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index aa40f85..ad25342 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -35,10 +35,12 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <string>
 #include <time.h>
+#include <wait.h>
 
 namespace android {
 namespace os {
@@ -51,6 +53,8 @@
  *      frameworks/base/core/proto/android/os/incident.proto
  */
 const int FIELD_ID_METADATA = 2;
+// Args for exec gzip
+static const char* GZIP[] = {"/system/bin/gzip", NULL};
 
 IncidentMetadata_Destination privacy_policy_to_dest(uint8_t privacyPolicy) {
     switch (privacyPolicy) {
@@ -142,7 +146,8 @@
          mListener(listener),
          mFd(fd),
          mIsStreaming(fd >= 0),
-         mStatus(NO_ERROR) {
+         mStatus(OK),
+         mZipPid(-1) {
 }
 
 ReportRequest::~ReportRequest() {
@@ -153,7 +158,14 @@
 }
 
 bool ReportRequest::ok() {
-    return mFd >= 0 && mStatus == NO_ERROR;
+    if (mStatus != OK) {
+        return false;
+    }
+    if (!args.gzip()) {
+        return mFd >= 0;
+    }
+    // Send a blank signal to check if mZipPid is alive
+    return mZipPid > 0 && kill(mZipPid, 0) == 0;
 }
 
 bool ReportRequest::containsSection(int sectionId) const {
@@ -161,10 +173,45 @@
 }
 
 void ReportRequest::closeFd() {
-    if (mIsStreaming && mFd >= 0) {
+    if (!mIsStreaming) {
+        return;
+    }
+    if (mFd >= 0) {
         close(mFd);
         mFd = -1;
     }
+    if (mZipPid > 0) {
+        mZipPipe.close();
+        // Gzip may take some time.
+        status_t err = wait_child(mZipPid, /* timeout_ms= */ 10 * 1000);
+        if (err != 0) {
+            ALOGW("[ReportRequest] abnormal child process: %s", strerror(-err));
+        }
+    }
+}
+
+int ReportRequest::getFd() {
+    return mZipPid > 0 ? mZipPipe.writeFd().get() : mFd;
+}
+
+status_t ReportRequest::initGzipIfNecessary() {
+    if (!mIsStreaming || !args.gzip()) {
+        return OK;
+    }
+    if (!mZipPipe.init()) {
+        ALOGE("[ReportRequest] Failed to setup pipe for gzip");
+        mStatus = -errno;
+        return mStatus;
+    }
+    int status = 0;
+    pid_t pid = fork_execute_cmd((char* const*)GZIP, mZipPipe.readFd().release(), mFd, &status);
+    if (pid < 0 || status != 0) {
+        mStatus = status;
+        return mStatus;
+    }
+    mZipPid = pid;
+    mFd = -1;
+    return OK;
 }
 
 // ================================================================================
@@ -562,6 +609,13 @@
         reportId = (spec.tv_sec) * 1000 + spec.tv_nsec;
     }
 
+    mBatch->forEachStreamingRequest([](const sp<ReportRequest>& request) {
+        status_t err = request->initGzipIfNecessary();
+        if (err != 0) {
+            ALOGW("Error forking gzip: %s", strerror(err));
+        }
+    });
+
     // Write the incident report headers - each request gets its own headers.  It's different
     // from the other top-level fields in IncidentReport that are the sections where the rest
     // is all shared data (although with their own individual privacy filtering).
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index cbc8b13..bd47a23 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include "incidentd_util.h"
 #include "FdBuffer.h"
 #include "WorkDirectory.h"
 
@@ -63,10 +64,12 @@
 
     sp<IIncidentReportStatusListener> getListener() { return mListener; }
 
-    int getFd() { return mFd; }
+    int getFd();
 
     int setPersistedFd(int fd);
 
+    status_t initGzipIfNecessary();
+
     void closeFd();
 
 private:
@@ -74,6 +77,8 @@
     int mFd;
     bool mIsStreaming;
     status_t mStatus;
+    pid_t mZipPid;
+    Fpipe mZipPipe;
 };
 
 // ================================================================================
diff --git a/cmds/incidentd/src/WorkDirectory.cpp b/cmds/incidentd/src/WorkDirectory.cpp
index 9963533..1944d6e 100644
--- a/cmds/incidentd/src/WorkDirectory.cpp
+++ b/cmds/incidentd/src/WorkDirectory.cpp
@@ -16,10 +16,10 @@
 
 #include "Log.h"
 
-#include "WorkDirectory.h"
-
+#include "incidentd_util.h"
 #include "proto_util.h"
 #include "PrivacyFilter.h"
+#include "WorkDirectory.h"
 
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <private/android_filesystem_config.h>
@@ -68,6 +68,9 @@
 /** metadata field id in IncidentProto */
 const int FIELD_ID_INCIDENT_METADATA = 2;
 
+// Args for exec gzip
+static const char* GZIP[] = {"/system/bin/gzip", NULL};
+
 /**
  * Read a protobuf from disk into the message.
  */
@@ -292,6 +295,7 @@
         report->set_cls(args.receiverCls());
         report->set_privacy_policy(args.getPrivacyPolicy());
         report->set_all_sections(args.all());
+        report->set_gzip(args.gzip());
         for (int section: args.sections()) {
             report->add_section(section);
         }
@@ -417,6 +421,24 @@
         return BAD_VALUE;
     }
 
+    pid_t zipPid = 0;
+    if (args.gzip()) {
+        Fpipe zipPipe;
+        if (!zipPipe.init()) {
+            ALOGE("[ReportFile] Failed to setup pipe for gzip");
+            close(writeFd);
+            return -errno;
+        }
+        int status = 0;
+        zipPid = fork_execute_cmd((char* const*)GZIP, zipPipe.readFd().release(), writeFd, &status);
+        close(writeFd);
+        if (zipPid < 0 || status != 0) {
+            ALOGE("[ReportFile] Failed to fork and exec gzip");
+            return status;
+        }
+        writeFd = zipPipe.writeFd().release();
+    }
+
     status_t err;
 
     for (const auto& report : mEnvelope.report()) {
@@ -437,6 +459,13 @@
     }
 
     close(writeFd);
+    if (zipPid > 0) {
+        status_t err = wait_child(zipPid, /* timeout_ms= */ 10 * 1000);
+        if (err != 0) {
+            ALOGE("[ReportFile] abnormal child process: %s", strerror(-err));
+        }
+        return err;
+    }
     return NO_ERROR;
 }
 
@@ -621,7 +650,7 @@
 
     map<string,WorkDirectoryEntry> files;
     get_directory_contents_locked(&files, 0);
-    
+
     for (map<string,WorkDirectoryEntry>::iterator it = files.begin();
             it != files.end(); it++) {
         sp<ReportFile> reportFile = new ReportFile(this, it->second.timestampNs,
@@ -815,6 +844,7 @@
     out->setAll(report.all_sections());
     out->setReceiverPkg(report.pkg());
     out->setReceiverCls(report.cls());
+    out->setGzip(report.gzip());
 
     const int sectionCount = report.section_size();
     for (int i = 0; i < sectionCount; i++) {
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index dfaf893..2649fb9 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -18,6 +18,7 @@
 
 #include "incidentd_util.h"
 
+#include <fcntl.h>
 #include <sys/prctl.h>
 #include <wait.h>
 
@@ -64,28 +65,52 @@
 
 unique_fd& Fpipe::writeFd() { return mWrite; }
 
-pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output) {
-    // fork used in multithreaded environment, avoid adding unnecessary code in child process
+pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output, int* status) {
+    int in = -1;
+    if (input != nullptr) {
+        in = input->readFd().release();
+        // Auto close write end of the input pipe on exec to prevent leaking fd in child process
+        fcntl(input->writeFd().get(), F_SETFD, FD_CLOEXEC);
+    }
+    int out = output->writeFd().release();
+    // Auto close read end of the output pipe on exec
+    fcntl(output->readFd().get(), F_SETFD, FD_CLOEXEC);
+    return fork_execute_cmd(argv, in, out, status);
+}
+
+pid_t fork_execute_cmd(char* const argv[], int in, int out, int* status) {
+    int dummy_status = 0;
+    if (status == nullptr) {
+        status = &dummy_status;
+    }
+    *status = 0;
     pid_t pid = fork();
+    if (pid < 0) {
+        *status = -errno;
+        return -1;
+    }
     if (pid == 0) {
-        if (input != NULL && (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 ||
-                              !input->close())) {
+        // In child
+        if (in >= 0 && (TEMP_FAILURE_RETRY(dup2(in, STDIN_FILENO)) < 0 || close(in))) {
             ALOGW("Failed to dup2 stdin.");
             _exit(EXIT_FAILURE);
         }
-        if (TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
-            !output->close()) {
+        if (TEMP_FAILURE_RETRY(dup2(out, STDOUT_FILENO)) < 0 || close(out)) {
             ALOGW("Failed to dup2 stdout.");
             _exit(EXIT_FAILURE);
         }
-        /* make sure the child dies when incidentd dies */
+        // Make sure the child dies when incidentd dies
         prctl(PR_SET_PDEATHSIG, SIGKILL);
         execvp(argv[0], argv);
         _exit(errno);  // always exits with failure if any
     }
-    // close the fds used in child process.
-    if (input != NULL) input->readFd().reset();
-    output->writeFd().reset();
+    // In parent
+    if ((in >= 0 && close(in) < 0) || close(out) < 0) {
+        ALOGW("Failed to close pd. Killing child process");
+        *status = -errno;
+        kill_child(pid);
+        return -1;
+    }
     return pid;
 }
 
@@ -120,9 +145,6 @@
 }
 
 // ================================================================================
-const int WAIT_MAX = 5;
-const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
-
 static status_t statusCode(int status) {
     if (WIFSIGNALED(status)) {
         VLOG("return by signal: %s", strerror(WTERMSIG(status)));
@@ -134,25 +156,64 @@
     return NO_ERROR;
 }
 
+static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
+    sigset_t child_mask, old_mask;
+    sigemptyset(&child_mask);
+    sigaddset(&child_mask, SIGCHLD);
+
+    if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
+        ALOGW("sigprocmask failed: %s", strerror(errno));
+        return false;
+    }
+
+    timespec ts;
+    ts.tv_sec = timeout_ms / 1000;
+    ts.tv_nsec = (timeout_ms % 1000) * 1000000;
+    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
+    int saved_errno = errno;
+
+    // Set the signals back the way they were.
+    if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
+        ALOGW("sigprocmask failed: %s", strerror(errno));
+        if (ret == 0) {
+            return false;
+        }
+    }
+    if (ret == -1) {
+        errno = saved_errno;
+        if (errno == EAGAIN) {
+            errno = ETIMEDOUT;
+        } else {
+            ALOGW("sigtimedwait failed: %s", strerror(errno));
+        }
+        return false;
+    }
+
+    pid_t child_pid = waitpid(pid, status, WNOHANG);
+    if (child_pid == pid) {
+        return true;
+    }
+    if (child_pid == -1) {
+        ALOGW("waitpid failed: %s", strerror(errno));
+    } else {
+        ALOGW("Waiting for pid %d, got pid %d instead", pid, child_pid);
+    }
+    return false;
+}
+
 status_t kill_child(pid_t pid) {
     int status;
-    VLOG("try to kill child process %d", pid);
     kill(pid, SIGKILL);
     if (waitpid(pid, &status, 0) == -1) return -1;
     return statusCode(status);
 }
 
-status_t wait_child(pid_t pid) {
+status_t wait_child(pid_t pid, int timeout_ms) {
     int status;
-    bool died = false;
-    // wait for child to report status up to 1 seconds
-    for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
-        if (waitpid(pid, &status, WNOHANG) == pid) died = true;
-        // sleep for 0.2 second
-        nanosleep(&WAIT_INTERVAL_NS, NULL);
+    if (waitpid_with_timeout(pid, timeout_ms, &status)) {
+        return statusCode(status);
     }
-    if (!died) return kill_child(pid);
-    return statusCode(status);
+    return kill_child(pid);
 }
 
 }  // namespace incidentd
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index cc30768..a54993fe 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -56,11 +56,24 @@
 };
 
 /**
- * Forks and exec a command with two pipes, one connects stdin for input,
- * one connects stdout for output. It returns the pid of the child.
- * Input pipe can be NULL to indicate child process doesn't read stdin.
+ * Forks and exec a command with two pipes and returns the pid of the child, or -1 when it fails.
+ *
+ * input connects stdin for input. output connects stdout for output. input can be nullptr to
+ * indicate that child process doesn't read stdin. This function will close in and out fds upon
+ * success. If status is not NULL, the status information will be stored in the int to which it
+ * points.
  */
-pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output);
+pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output, int* status = nullptr);
+
+/**
+ * Forks and exec a command that reads from in fd and writes to out fd and returns the pid of the
+ * child, or -1 when it fails.
+ *
+ * in can be -1 to indicate that child process doesn't read stdin. This function will close in and
+ * out fds upon success. If status is not NULL, the status information will be stored in the int
+ * to which it points.
+ */
+pid_t fork_execute_cmd(char* const argv[], int in, int out, int* status = nullptr);
 
 /**
  * Grabs varargs from stack and stores them in heap with NULL-terminated array.
@@ -76,7 +89,7 @@
  * Methods to wait or kill child process, return exit status code.
  */
 status_t kill_child(pid_t pid);
-status_t wait_child(pid_t pid);
+status_t wait_child(pid_t pid, int timeout_ms = 1000);
 
 status_t start_detached_thread(const function<void ()>& func);
 
diff --git a/cmds/incidentd/src/report_file.proto b/cmds/incidentd/src/report_file.proto
index 7563da2..85fd2da 100644
--- a/cmds/incidentd/src/report_file.proto
+++ b/cmds/incidentd/src/report_file.proto
@@ -65,6 +65,11 @@
          * the given client.
          */
         optional bool share_approved = 8;
+
+        /**
+         * Whether the report is gzipped.
+         */
+        optional bool gzip = 9;
     }
 
     /**
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 0c3a49a9..bd6ca47 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -122,7 +122,6 @@
         "libbinder_ndk",
         "libincident",
         "liblog",
-        "libstatssocket",
         "statsd-aidl-ndk_platform",
     ],
 }
@@ -165,10 +164,6 @@
     export_generated_headers: [
         "atoms_info.h",
     ],
-    shared_libs: [
-        "libcutils",
-        "libstatslog",
-    ],
     apex_available: [
         //TODO(b/149782403): Remove this once statsd no longer links against libstatsmetadata
         "com.android.os.statsd",
@@ -215,7 +210,10 @@
         type: "lite",
     },
 
-    shared_libs: ["libgtest_prod"],
+    shared_libs: [
+        "libgtest_prod",
+        "libstatssocket",
+    ],
 
     apex_available: [
         "com.android.os.statsd",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 7ab6c71..f18aaa5 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1196,13 +1196,14 @@
     return Status::ok();
 }
 
-Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
-                                    int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
-                                    const shared_ptr<IPullAtomCallback>& pullerCallback) {
+Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownMillis,
+                                              int64_t timeoutMillis,
+                                              const std::vector<int32_t>& additiveFields,
+                                              const shared_ptr<IPullAtomCallback>& pullerCallback) {
     ENFORCE_UID(AID_SYSTEM);
-
     VLOG("StatsService::registerPullAtomCallback called.");
-    mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields,
+    mPullerManager->RegisterPullAtomCallback(uid, atomTag, MillisToNano(coolDownMillis),
+                                             MillisToNano(timeoutMillis), additiveFields,
                                              pullerCallback);
     return Status::ok();
 }
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index e6723c8..c256e1f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -167,8 +167,9 @@
     /**
      * Binder call to register a callback function for a pulled atom.
      */
-    virtual Status registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
-            int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+    virtual Status registerPullAtomCallback(
+            int32_t uid, int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
+            const std::vector<int32_t>& additiveFields,
             const shared_ptr<IPullAtomCallback>& pullerCallback) override;
 
     /**
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 9c875ba..40a24dc 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -116,5 +116,5 @@
 
     optional bool allow_from_any_uid = 50003 [default = false];
 
-    optional string module = 50004;
+    repeated string module = 50004;
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e58e7bc..9645a46 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3600,9 +3600,10 @@
     // See NotificationSectionsManager.PriorityBucket.
     enum NotificationSection {
         SECTION_UNKNOWN = 0;
-        SECTION_PEOPLE = 1;
-        SECTION_ALERTING = 2;
-        SECTION_SILENT = 3;
+        SECTION_HEADS_UP = 1;
+        SECTION_PEOPLE = 2;
+        SECTION_ALERTING = 3;
+        SECTION_SILENT = 4;
     }
     optional NotificationSection section = 6;
 }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a53fc35..2399e37 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,10 +16,6 @@
 
 package android.app;
 
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
-
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
@@ -74,6 +70,7 @@
 import com.android.internal.os.ZygoteInit;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DataClass;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.Parcelling;
 import com.android.internal.util.Preconditions;
 
@@ -666,15 +663,31 @@
         }
     }
 
+    // These constants are redefined here to work around a metalava limitation/bug where
+    // @IntDef is not able to see @hide symbols when they are hidden via package hiding:
+    // frameworks/base/core/java/com/android/internal/package.html
+
+    /** @hide */
+    public static final int SAMPLING_STRATEGY_DEFAULT =
+            FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT;
+
+    /** @hide */
+    public static final int SAMPLING_STRATEGY_UNIFORM =
+            FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
+
+    /** @hide */
+    public static final int SAMPLING_STRATEGY_RARELY_USED =
+            FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
+
     /**
      * Strategies used for message sampling
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"RUNTIME_APP_OPS_ACCESS__SAMPLING_STRATEGY__"}, value = {
-            RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT,
-            RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM,
-            RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED
+    @IntDef(prefix = {"SAMPLING_STRATEGY_"}, value = {
+            SAMPLING_STRATEGY_DEFAULT,
+            SAMPLING_STRATEGY_UNIFORM,
+            SAMPLING_STRATEGY_RARELY_USED
     })
     public @interface SamplingStrategy {}
 
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index c55453e..5df3257 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.CurrentTimeMillisLong;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -121,11 +122,30 @@
     public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9;
 
     /**
-     * Application process was killed by the system for various other reasons,
-     * for example, the application package got disabled by the user;
-     * {@link #getDescription} will specify the cause given by the system.
+     * Application process was killed because of the user request, for example,
+     * user clicked the "Force stop" button of the application in the Settings,
+     * or removed the application away from Recents.
      */
-    public static final int REASON_OTHER = 10;
+    public static final int REASON_USER_REQUESTED = 10;
+
+    /**
+     * Application process was killed, because the user it is running as on devices
+     * with mutlple users, was stopped.
+     */
+    public static final int REASON_USER_STOPPED = 11;
+
+    /**
+     * Application process was killed because its dependency was going away, for example,
+     * a stable content provider connection's client will be killed if the provider is killed.
+     */
+    public static final int REASON_DEPENDENCY_DIED = 12;
+
+    /**
+     * Application process was killed by the system for various other reasons which are
+     * not by problems in apps and not actionable by apps, for example, the system just
+     * finished updates; {@link #getDescription} will specify the cause given by the system.
+     */
+    public static final int REASON_OTHER = 13;
 
     /**
      * Application process kills subreason is unknown.
@@ -202,6 +222,105 @@
     public static final int SUBREASON_EXCESSIVE_CPU = 7;
 
     /**
+     * System update has done (so the system update process should be killed);
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_SYSTEM_UPDATE_DONE = 8;
+
+    /**
+     * Kill all foreground services, for now it only occurs when enabling the quiet
+     * mode for the managed profile;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_KILL_ALL_FG = 9;
+
+    /**
+     * All background processes except certain ones were killed, for now it only occurs
+     * when the density of the default display is changed;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_KILL_ALL_BG_EXCEPT = 10;
+
+    /**
+     * The process associated with the UID was explicitly killed, for example,
+     * it could be because of platform compatibility overrides;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_KILL_UID = 11;
+
+    /**
+     * The process was explicitly killed with its PID, typically because of
+     * the low memory for surfaces;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_KILL_PID = 12;
+
+    /**
+     * The start of the process was invalid;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_INVALID_START = 13;
+
+    /**
+     * The process was killed because it's in an invalid state, typically
+     * it's triggered from SHELL;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_INVALID_STATE = 14;
+
+    /**
+     * The process was killed when it's imperceptible to user, because it was
+     * in a bad state;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_IMPERCEPTIBLE = 15;
+
+    /**
+     * The process was killed because it's being moved out from LRU list;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_REMOVE_LRU = 16;
+
+    /**
+     * The process was killed because it's isolated and was in a cached state;
+     * this would be set only when the reason is {@link #REASON_OTHER}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_ISOLATED_NOT_NEEDED = 17;
+
+    // If there is any OEM code which involves additional app kill reasons, it should
+    // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
+
+    /**
      * @see {@link #getPid}
      */
     private int mPid;
@@ -254,7 +373,7 @@
     /**
      * @see {@link #getTimestamp}
      */
-    private long mTimestamp;
+    private @CurrentTimeMillisLong long mTimestamp;
 
     /**
      * @see {@link #getDescription}
@@ -293,6 +412,9 @@
         REASON_INITIALIZATION_FAILURE,
         REASON_PERMISSION_CHANGE,
         REASON_EXCESSIVE_RESOURCE_USAGE,
+        REASON_USER_REQUESTED,
+        REASON_USER_STOPPED,
+        REASON_DEPENDENCY_DIED,
         REASON_OTHER,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -308,6 +430,16 @@
         SUBREASON_LARGE_CACHED,
         SUBREASON_MEMORY_PRESSURE,
         SUBREASON_EXCESSIVE_CPU,
+        SUBREASON_SYSTEM_UPDATE_DONE,
+        SUBREASON_KILL_ALL_FG,
+        SUBREASON_KILL_ALL_BG_EXCEPT,
+        SUBREASON_KILL_UID,
+        SUBREASON_KILL_PID,
+        SUBREASON_INVALID_START,
+        SUBREASON_INVALID_STATE,
+        SUBREASON_IMPERCEPTIBLE,
+        SUBREASON_REMOVE_LRU,
+        SUBREASON_ISOLATED_NOT_NEEDED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SubReason {}
@@ -403,7 +535,7 @@
      * The timestamp of the process's death, in milliseconds since the epoch,
      * as returned by {@link System#currentTimeMillis System.currentTimeMillis()}.
      */
-    public long getTimestamp() {
+    public @CurrentTimeMillisLong long getTimestamp() {
         return mTimestamp;
     }
 
@@ -564,7 +696,7 @@
      *
      * @hide
      */
-    public void setTimestamp(final long timestamp) {
+    public void setTimestamp(final @CurrentTimeMillisLong long timestamp) {
         mTimestamp = timestamp;
     }
 
@@ -656,6 +788,8 @@
         mRss = other.mRss;
         mTimestamp = other.mTimestamp;
         mDescription = other.mDescription;
+        mPackageName = other.mPackageName;
+        mPackageList = other.mPackageList;
     }
 
     private ApplicationExitInfo(@NonNull Parcel in) {
@@ -748,6 +882,12 @@
                 return "PERMISSION CHANGE";
             case REASON_EXCESSIVE_RESOURCE_USAGE:
                 return "EXCESSIVE RESOURCE USAGE";
+            case REASON_USER_REQUESTED:
+                return "USER REQUESTED";
+            case REASON_USER_STOPPED:
+                return "USER STOPPED";
+            case REASON_DEPENDENCY_DIED:
+                return "DEPENDENCY DIED";
             case REASON_OTHER:
                 return "OTHER KILLS BY SYSTEM";
             default:
@@ -772,6 +912,26 @@
                 return "MEMORY PRESSURE";
             case SUBREASON_EXCESSIVE_CPU:
                 return "EXCESSIVE CPU USAGE";
+            case SUBREASON_SYSTEM_UPDATE_DONE:
+                return "SYSTEM UPDATE_DONE";
+            case SUBREASON_KILL_ALL_FG:
+                return "KILL ALL FG";
+            case SUBREASON_KILL_ALL_BG_EXCEPT:
+                return "KILL ALL BG EXCEPT";
+            case SUBREASON_KILL_UID:
+                return "KILL UID";
+            case SUBREASON_KILL_PID:
+                return "KILL PID";
+            case SUBREASON_INVALID_START:
+                return "INVALID START";
+            case SUBREASON_INVALID_STATE:
+                return "INVALID STATE";
+            case SUBREASON_IMPERCEPTIBLE:
+                return "IMPERCEPTIBLE";
+            case SUBREASON_REMOVE_LRU:
+                return "REMOVE LRU";
+            case SUBREASON_ISOLATED_NOT_NEEDED:
+                return "ISOLATED NOT NEEDED";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index be07b37..a3bcc9ce 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,7 +23,6 @@
 import android.app.ContextImpl.ServiceInitializationState;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
-import android.app.appsearch.AppSearchManagerFrameworkInitializer;
 import android.app.blob.BlobStoreManagerFrameworkInitializer;
 import android.app.contentsuggestions.ContentSuggestionsManager;
 import android.app.contentsuggestions.IContentSuggestionsManager;
@@ -1343,7 +1342,6 @@
             JobSchedulerFrameworkInitializer.registerServiceWrappers();
             BlobStoreManagerFrameworkInitializer.initialize();
             TelephonyFrameworkInitializer.registerServiceWrappers();
-            AppSearchManagerFrameworkInitializer.initialize();
             WifiFrameworkInitializer.registerServiceWrappers();
             StatsFrameworkInitializer.registerServiceWrappers();
         } finally {
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index d8c653c6..b672a08 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -643,8 +643,9 @@
     @SystemApi
     @Nullable
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothCodecStatus getCodecStatus(@Nullable BluetoothDevice device) {
+    public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
         if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
+        verifyDeviceNotNull(device, "getCodecStatus");
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled()) {
@@ -670,9 +671,14 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public void setCodecConfigPreference(@Nullable BluetoothDevice device,
-                                         @Nullable BluetoothCodecConfig codecConfig) {
+    public void setCodecConfigPreference(@NonNull BluetoothDevice device,
+                                         @NonNull BluetoothCodecConfig codecConfig) {
         if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
+        verifyDeviceNotNull(device, "setCodecConfigPreference");
+        if (codecConfig == null) {
+            Log.e(TAG, "setCodecConfigPreference: Codec config can't be null");
+            throw new IllegalArgumentException("codecConfig cannot be null");
+        }
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled()) {
@@ -695,8 +701,9 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public void enableOptionalCodecs(@Nullable BluetoothDevice device) {
+    public void enableOptionalCodecs(@NonNull BluetoothDevice device) {
         if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
+        verifyDeviceNotNull(device, "enableOptionalCodecs");
         enableDisableOptionalCodecs(device, true);
     }
 
@@ -709,8 +716,9 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public void disableOptionalCodecs(@Nullable BluetoothDevice device) {
+    public void disableOptionalCodecs(@NonNull BluetoothDevice device) {
         if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
+        verifyDeviceNotNull(device, "disableOptionalCodecs");
         enableDisableOptionalCodecs(device, false);
     }
 
@@ -750,7 +758,8 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     @OptionalCodecsSupportStatus
-    public int supportsOptionalCodecs(@Nullable BluetoothDevice device) {
+    public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) {
+        verifyDeviceNotNull(device, "isOptionalCodecsSupported");
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled() && isValidDevice(device)) {
@@ -775,7 +784,8 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     @OptionalCodecsPreferenceStatus
-    public int getOptionalCodecsEnabled(@Nullable BluetoothDevice device) {
+    public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) {
+        verifyDeviceNotNull(device, "isOptionalCodecsEnabled");
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled() && isValidDevice(device)) {
@@ -800,8 +810,9 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public void setOptionalCodecsEnabled(@Nullable BluetoothDevice device,
+    public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device,
             @OptionalCodecsPreferenceStatus int value) {
+        verifyDeviceNotNull(device, "setOptionalCodecsEnabled");
         try {
             if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
                     && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
@@ -854,6 +865,13 @@
         return false;
     }
 
+    private void verifyDeviceNotNull(BluetoothDevice device, String methodName) {
+        if (device == null) {
+            Log.e(TAG, methodName + ": device param is null");
+            throw new IllegalArgumentException("Device cannot be null");
+        }
+    }
+
     private boolean isValidDevice(BluetoothDevice device) {
         if (device == null) return false;
 
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index c7f42cb..ae786aa 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -629,7 +629,10 @@
     /** @hide */
     @IntDef(flag = true, prefix = { "NOTIFY_" }, value = {
             NOTIFY_SYNC_TO_NETWORK,
-            NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
+            NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS,
+            NOTIFY_INSERT,
+            NOTIFY_UPDATE,
+            NOTIFY_DELETE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface NotifyFlags {}
@@ -651,6 +654,36 @@
     public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
 
     /**
+     * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set
+     * by a {@link ContentProvider} to indicate that this notification is the
+     * result of an {@link ContentProvider#insert} call.
+     * <p>
+     * Sending these detailed flags are optional, but providers are strongly
+     * recommended to send them.
+     */
+    public static final int NOTIFY_INSERT = 1 << 2;
+
+    /**
+     * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set
+     * by a {@link ContentProvider} to indicate that this notification is the
+     * result of an {@link ContentProvider#update} call.
+     * <p>
+     * Sending these detailed flags are optional, but providers are strongly
+     * recommended to send them.
+     */
+    public static final int NOTIFY_UPDATE = 1 << 3;
+
+    /**
+     * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set
+     * by a {@link ContentProvider} to indicate that this notification is the
+     * result of a {@link ContentProvider#delete} call.
+     * <p>
+     * Sending these detailed flags are optional, but providers are strongly
+     * recommended to send them.
+     */
+    public static final int NOTIFY_DELETE = 1 << 4;
+
+    /**
      * No exception, throttled by app standby normally.
      * @hide
      */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a8f7610..aba86e9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5109,16 +5109,6 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
-     * {@link android.app.appsearch.AppSearchManager} for
-     * indexing and querying app data managed by the system.
-     *
-     * @see #getSystemService(String)
-     * @hide
-     */
-    public static final String APP_SEARCH_SERVICE = "app_search";
-
-    /**
-     * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.content.integrity.AppIntegrityManager}.
      * @hide
      */
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index 69ca581..ede264d 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -16,11 +16,17 @@
 
 package android.database;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ContentResolver.NotifyFlags;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 
+import java.util.Arrays;
+
 /**
  * Receives call backs for changes to content.
  * Must be implemented by objects which are added to a {@link ContentObservable}.
@@ -101,12 +107,10 @@
      * This method is called when a content change occurs.
      * Includes the changed content Uri when available.
      * <p>
-     * Subclasses should override this method to handle content changes.
-     * To ensure correct operation on older versions of the framework that
-     * did not provide a Uri argument, applications should also implement
-     * the {@link #onChange(boolean)} overload of this method whenever they
-     * implement the {@link #onChange(boolean, Uri)} overload.
-     * </p><p>
+     * Subclasses should override this method to handle content changes. To
+     * ensure correct operation on older versions of the framework that did not
+     * provide richer arguments, applications should implement all overloads.
+     * <p>
      * Example implementation:
      * <pre><code>
      * // Implement the onChange(boolean) method to delegate the change notification to
@@ -126,38 +130,63 @@
      * </p>
      *
      * @param selfChange True if this is a self-change notification.
-     * @param uri The Uri of the changed content, or null if unknown.
+     * @param uri The Uri of the changed content.
      */
-    public void onChange(boolean selfChange, Uri uri) {
+    public void onChange(boolean selfChange, @Nullable Uri uri) {
         onChange(selfChange);
     }
 
     /**
-     * Dispatches a change notification to the observer. Includes the changed
-     * content Uri when available and also the user whose content changed.
+     * This method is called when a content change occurs. Includes the changed
+     * content Uri when available.
+     * <p>
+     * Subclasses should override this method to handle content changes. To
+     * ensure correct operation on older versions of the framework that did not
+     * provide richer arguments, applications should implement all overloads.
      *
      * @param selfChange True if this is a self-change notification.
-     * @param uri The Uri of the changed content, or null if unknown.
-     * @param userId The user whose content changed. Can be either a specific
-     *         user or {@link UserHandle#USER_ALL}.
-     *
-     * @hide
+     * @param uri The Uri of the changed content.
+     * @param flags Flags indicating details about this change.
      */
-    public void onChange(boolean selfChange, Uri uri, int userId) {
+    public void onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags) {
         onChange(selfChange, uri);
     }
 
     /**
+     * This method is called when a content change occurs. Includes the changed
+     * content Uris when available.
+     * <p>
+     * Subclasses should override this method to handle content changes. To
+     * ensure correct operation on older versions of the framework that did not
+     * provide richer arguments, applications should implement all overloads.
+     *
+     * @param selfChange True if this is a self-change notification.
+     * @param uris The Uris of the changed content.
+     * @param flags Flags indicating details about this change.
+     */
+    public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags) {
+        for (Uri uri : uris) {
+            onChange(selfChange, uri, flags);
+        }
+    }
+
+    /** @hide */
+    public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags,
+            @UserIdInt int userId) {
+        onChange(selfChange, uris, flags);
+    }
+
+    /**
      * Dispatches a change notification to the observer.
      * <p>
-     * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
-     * then a call to the {@link #onChange} method is posted to the handler's message queue.
-     * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
-     * </p>
+     * If a {@link Handler} was supplied to the {@link ContentObserver}
+     * constructor, then a call to the {@link #onChange} method is posted to the
+     * handler's message queue. Otherwise, the {@link #onChange} method is
+     * invoked immediately on this thread.
      *
-     * @param selfChange True if this is a self-change notification.
-     *
-     * @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
+     * @deprecated Callers should migrate towards using a richer overload that
+     *             provides more details about the change, such as
+     *             {@link #dispatchChange(boolean, Iterable, int)}.
      */
     @Deprecated
     public final void dispatchChange(boolean selfChange) {
@@ -165,57 +194,66 @@
     }
 
     /**
-     * Dispatches a change notification to the observer.
-     * Includes the changed content Uri when available.
+     * Dispatches a change notification to the observer. Includes the changed
+     * content Uri when available.
      * <p>
-     * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
-     * then a call to the {@link #onChange} method is posted to the handler's message queue.
-     * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
-     * </p>
+     * If a {@link Handler} was supplied to the {@link ContentObserver}
+     * constructor, then a call to the {@link #onChange} method is posted to the
+     * handler's message queue. Otherwise, the {@link #onChange} method is
+     * invoked immediately on this thread.
      *
      * @param selfChange True if this is a self-change notification.
-     * @param uri The Uri of the changed content, or null if unknown.
+     * @param uri The Uri of the changed content.
      */
-    public final void dispatchChange(boolean selfChange, Uri uri) {
-        dispatchChange(selfChange, uri, UserHandle.getCallingUserId());
+    public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
+        dispatchChange(selfChange, Arrays.asList(uri), 0, UserHandle.getCallingUserId());
     }
 
     /**
      * Dispatches a change notification to the observer. Includes the changed
-     * content Uri when available and also the user whose content changed.
+     * content Uri when available.
      * <p>
-     * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
-     * then a call to the {@link #onChange} method is posted to the handler's message queue.
-     * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
-     * </p>
+     * If a {@link Handler} was supplied to the {@link ContentObserver}
+     * constructor, then a call to the {@link #onChange} method is posted to the
+     * handler's message queue. Otherwise, the {@link #onChange} method is
+     * invoked immediately on this thread.
      *
      * @param selfChange True if this is a self-change notification.
-     * @param uri The Uri of the changed content, or null if unknown.
-     * @param userId The user whose content changed.
+     * @param uri The Uri of the changed content.
+     * @param flags Flags indicating details about this change.
      */
-    private void dispatchChange(boolean selfChange, Uri uri, int userId) {
-        if (mHandler == null) {
-            onChange(selfChange, uri, userId);
-        } else {
-            mHandler.post(new NotificationRunnable(selfChange, uri, userId));
-        }
+    public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
+            @NotifyFlags int flags) {
+        dispatchChange(selfChange, Arrays.asList(uri), flags, UserHandle.getCallingUserId());
     }
 
+    /**
+     * Dispatches a change notification to the observer. Includes the changed
+     * content Uris when available.
+     * <p>
+     * If a {@link Handler} was supplied to the {@link ContentObserver}
+     * constructor, then a call to the {@link #onChange} method is posted to the
+     * handler's message queue. Otherwise, the {@link #onChange} method is
+     * invoked immediately on this thread.
+     *
+     * @param selfChange True if this is a self-change notification.
+     * @param uris The Uri of the changed content.
+     * @param flags Flags indicating details about this change.
+     */
+    public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+            @NotifyFlags int flags) {
+        dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
+    }
 
-    private final class NotificationRunnable implements Runnable {
-        private final boolean mSelfChange;
-        private final Uri mUri;
-        private final int mUserId;
-
-        public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
-            mSelfChange = selfChange;
-            mUri = uri;
-            mUserId = userId;
-        }
-
-        @Override
-        public void run() {
-            ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
+    /** @hide */
+    public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+            @NotifyFlags int flags, @UserIdInt int userId) {
+        if (mHandler == null) {
+            onChange(selfChange, uris, flags, userId);
+        } else {
+            mHandler.post(() -> {
+                onChange(selfChange, uris, flags, userId);
+            });
         }
     }
 
@@ -228,9 +266,16 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
+            // This is kept intact purely for apps using hidden APIs, to
+            // redirect to the updated implementation
+            onChangeEtc(selfChange, new Uri[] { uri }, 0, userId);
+        }
+
+        @Override
+        public void onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId) {
             ContentObserver contentObserver = mContentObserver;
             if (contentObserver != null) {
-                contentObserver.dispatchChange(selfChange, uri, userId);
+                contentObserver.dispatchChange(selfChange, Arrays.asList(uris), flags, userId);
             }
         }
 
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 02eddf2..1855dd2 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -16,9 +16,14 @@
 
 package android.database;
 
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.ContentResolver.NotifyFlags;
 import android.net.Uri;
 import android.os.*;
 
+import java.util.ArrayList;
+
 
 /**
  * Wraps a BulkCursor around an existing Cursor making it remotable.
@@ -76,9 +81,18 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, Uri uri) {
+        public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+                @NotifyFlags int flags, @UserIdInt int userId) {
+            // Since we deliver changes from the most-specific to least-specific
+            // overloads, we only need to redirect from the most-specific local
+            // method to the most-specific remote method
+
+            final ArrayList<Uri> asList = new ArrayList<>();
+            uris.forEach(asList::add);
+            final Uri[] asArray = asList.toArray(new Uri[asList.size()]);
+
             try {
-                mRemote.onChange(selfChange, uri, android.os.Process.myUid());
+                mRemote.onChangeEtc(selfChange, asArray, flags, userId);
             } catch (RemoteException ex) {
                 // Do nothing, the far side is dead
             }
diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl
index 6235566..19284cf 100644
--- a/core/java/android/database/IContentObserver.aidl
+++ b/core/java/android/database/IContentObserver.aidl
@@ -22,8 +22,7 @@
 /**
  * @hide
  */
-interface IContentObserver
-{
+interface IContentObserver {
     /**
      * This method is called when an update occurs to the cursor that is being
      * observed. selfUpdate is true if the update was caused by a call to
@@ -31,4 +30,11 @@
      */
     @UnsupportedAppUsage
     oneway void onChange(boolean selfUpdate, in Uri uri, int userId);
+
+    /**
+     * This method is called when an update occurs to the cursor that is being
+     * observed. selfUpdate is true if the update was caused by a call to
+     * commit on the cursor that is being observed.
+     */
+    oneway void onChangeEtc(boolean selfUpdate, in Uri[] uri, int flags, int userId);
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 9e639346..1b6c1ee 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -611,6 +611,10 @@
         public void unbindInput() {
             if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
                     + " ic=" + mInputConnection);
+            // Unbind input is per process per display.
+            // TODO(b/150902448): free-up IME surface when target is changing.
+            //  e.g. DisplayContent#setInputMethodTarget()
+            removeImeSurface();
             onUnbindInput();
             mInputBinding = null;
             mInputConnection = null;
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index f2e16b4..a9585c6 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -350,12 +350,13 @@
     /**
      * Indicates that an app has acquired the wifi multicast lock.
      *
-     * @param uid UID of the app that acquired the wifi lock (to be used for battery blaming).
+     * @param ws Worksource with the uid of the app that acquired the wifi lock (to be used for
+     *           battery blaming).
      */
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
-    public void reportWifiMulticastEnabled(int uid) {
+    public void reportWifiMulticastEnabled(@NonNull WorkSource ws) {
         try {
-            mBatteryStats.noteWifiMulticastEnabled(uid);
+            mBatteryStats.noteWifiMulticastEnabled(ws.getAttributionUid());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -364,12 +365,13 @@
     /**
      * Indicates that an app has released the wifi multicast lock.
      *
-     * @param uid UID of the app that released the wifi lock (to be used for battery blaming).
+     * @param ws Worksource with the uid of the app that released the wifi lock (to be used for
+     *           battery blaming).
      */
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
-    public void reportWifiMulticastDisabled(int uid) {
+    public void reportWifiMulticastDisabled(@NonNull WorkSource ws) {
         try {
-            mBatteryStats.noteWifiMulticastDisabled(uid);
+            mBatteryStats.noteWifiMulticastDisabled(ws.getAttributionUid());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 223f920..de274c0 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -559,6 +559,37 @@
         }
     }
 
+    private static class CleanupAppliedPayloadCallback extends IUpdateEngineCallback.Stub {
+        private int mErrorCode = ErrorCodeConstants.ERROR;
+        private boolean mCompleted = false;
+        private Object mLock = new Object();
+        private int getResult() {
+            synchronized (mLock) {
+                while (!mCompleted) {
+                    try {
+                        mLock.wait();
+                    } catch (InterruptedException ex) {
+                        // do nothing, just wait again.
+                    }
+                }
+                return mErrorCode;
+            }
+        }
+
+        @Override
+        public void onStatusUpdate(int status, float percent) {
+        }
+
+        @Override
+        public void onPayloadApplicationComplete(int errorCode) {
+            synchronized (mLock) {
+                mErrorCode = errorCode;
+                mCompleted = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
     /**
      * Cleanup files used by the previous update and free up space after the
      * device has been booted successfully into the new build.
@@ -590,8 +621,10 @@
     @WorkerThread
     @ErrorCode
     public int cleanupAppliedPayload() {
+        CleanupAppliedPayloadCallback callback = new CleanupAppliedPayloadCallback();
         try {
-            return mUpdateEngine.cleanupSuccessfulUpdate();
+            mUpdateEngine.cleanupSuccessfulUpdate(callback);
+            return callback.getResult();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index 3c30f63..7e6ebcf 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -215,7 +215,7 @@
      * Returns the number of bytes transmitted over wifi within
      * {@link #getLoggingDurationMillis()}.
      *
-     * @return Number of packets received.
+     * @return Number of bytes transmitted.
      */
     public long getNumBytesTx() {
         return mNumBytesTx;
@@ -225,7 +225,7 @@
      * Returns the number of packets received over wifi within
      * {@link #getLoggingDurationMillis()}.
      *
-     * @return Number of bytes transmitted.
+     * @return Number of packets received.
      */
     public long getNumPacketsRx() {
         return mNumPacketsRx;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4216cf3..83a304f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6608,6 +6608,18 @@
                 "accessibility_button_target_component";
 
         /**
+         * Setting specifying the accessibility services, accessibility shortcut targets,
+         * or features to be toggled via the long press accessibility button in the navigation bar.
+         *
+         * <p> This is a colon-separated string list which contains the flattened
+         * {@link ComponentName} and the class name of a system class implementing a supported
+         * accessibility feature.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS =
+                "accessibility_button_long_press_targets";
+
+        /**
          * The system class name of magnification controller which is a target to be toggled via
          * accessibility shortcut or accessibility button.
          *
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index dabd977..d01bc25 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -395,7 +395,7 @@
      * {@link ControlsProviderService#createPublisherForAllAvailable}:
      * <ul>
      *     <li> Status: {@link Status#STATUS_UNKNOWN}
-     *     <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+     *     <li> Control template: {@link ControlTemplate#getNoTemplateObject}
      *     <li> Status text: {@code ""}
      * </ul>
      */
@@ -593,7 +593,7 @@
      *     <li> Title: {@code ""}
      *     <li> Subtitle: {@code ""}
      *     <li> Status: {@link Status#STATUS_UNKNOWN}
-     *     <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+     *     <li> Control template: {@link ControlTemplate#getNoTemplateObject}
      *     <li> Status text: {@code ""}
      * </ul>
      */
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index 9debb37..9accf5b 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -239,7 +239,8 @@
 
     private static boolean isStatelessControl(Control control) {
         return (control.getStatus() == Control.STATUS_UNKNOWN
-                && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE
+                && control.getControlTemplate().getTemplateType()
+                == ControlTemplate.TYPE_NO_TEMPLATE
                 && TextUtils.isEmpty(control.getStatusText()));
     }
 
diff --git a/core/java/android/service/controls/DeviceTypes.java b/core/java/android/service/controls/DeviceTypes.java
index 6594d2c..f973610 100644
--- a/core/java/android/service/controls/DeviceTypes.java
+++ b/core/java/android/service/controls/DeviceTypes.java
@@ -23,11 +23,23 @@
 
 /**
  * Device types for {@link Control}.
+ *
+ * Each {@link Control} declares a type for the device they represent. This type will be used to
+ * determine icons and colors.
+ * <p>
+ * The type of the device may change on status updates of the {@link Control}. For example, a
+ * device of {@link #TYPE_OUTLET} could be determined by the {@link ControlsProviderService} to be
+ * a {@link #TYPE_COFFEE_MAKER} and change the type for that {@link Control}, therefore possibly
+ * changing icon and color.
+ * <p>
+ * In case the device type is not know by the application but the basic function is, or there is no
+ * provided type, one of the generic types (those starting with {@code TYPE_GENERIC}) can be used.
+ * These will provide an identifiable icon based on the basic function of the device.
  */
 public class DeviceTypes {
 
     // Update this when adding new concrete types. Does not count TYPE_UNKNOWN
-    private static final int NUM_CONCRETE_TYPES = 51;
+    private static final int NUM_CONCRETE_TYPES = 52;
 
     public static final @DeviceType int TYPE_UNKNOWN = 0;
     public static final @DeviceType int TYPE_AC_HEATER = 1;
@@ -87,6 +99,11 @@
     public static final @DeviceType int TYPE_CAMERA = 50;
     public static final @DeviceType int TYPE_DOORBELL = 51;
 
+    /*
+     * Also known as macros, routines can aggregate a series of actions across multiple devices
+     */
+    public static final @DeviceType int TYPE_ROUTINE = 52;
+
     // Update this when adding new generic types.
     private static final int NUM_GENERIC_TYPES = 7;
     public static final @DeviceType int TYPE_GENERIC_ON_OFF = -1;
@@ -165,7 +182,8 @@
             TYPE_REFRIGERATOR,
             TYPE_THERMOSTAT,
             TYPE_CAMERA,
-            TYPE_DOORBELL
+            TYPE_DOORBELL,
+            TYPE_ROUTINE
             })
     public @interface DeviceType {}
 
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 45e63d7..37a75f0 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -22,7 +22,7 @@
 import android.annotation.Nullable;
 import android.os.Bundle;
 import android.service.controls.Control;
-import android.service.controls.IControlsActionCallback;
+import android.service.controls.ControlsProviderService;
 import android.service.controls.templates.ControlTemplate;
 import android.util.Log;
 
@@ -34,8 +34,15 @@
 /**
  * An abstract action indicating a user interaction with a {@link Control}.
  *
- * The action may have a value to authenticate the input, when the provider has requested it to
- * complete the action.
+ * In some cases, an action needs to be validated by the user, using a password, PIN or simple
+ * acknowledgment. For those cases, an optional (nullable) parameter can be passed to send the user
+ * input. This <b>challenge value</b> will be requested from the user and sent as part
+ * of a {@link ControlAction} only if the service has responded to an action with one of:
+ * <ul>
+ *     <li> {@link #RESPONSE_CHALLENGE_ACK}
+ *     <li> {@link #RESPONSE_CHALLENGE_PIN}
+ *     <li> {@link #RESPONSE_CHALLENGE_PASSPHRASE}
+ * </ul>
  */
 public abstract class ControlAction {
 
@@ -53,7 +60,6 @@
             TYPE_ERROR,
             TYPE_BOOLEAN,
             TYPE_FLOAT,
-            TYPE_MULTI_FLOAT,
             TYPE_MODE,
             TYPE_COMMAND
     })
@@ -61,6 +67,7 @@
 
     /**
      * Object returned when there is an unparcelling error.
+     * @hide
      */
     public static final @NonNull ControlAction ERROR_ACTION = new ControlAction() {
         @Override
@@ -70,7 +77,7 @@
     };
 
     /**
-     * The identifier of {@link #ERROR_ACTION}
+     * The identifier of the action returned by {@link #getErrorAction}.
      */
     public static final @ActionType int TYPE_ERROR = -1;
 
@@ -85,11 +92,6 @@
     public static final @ActionType int TYPE_FLOAT = 2;
 
     /**
-     * The identifier of {@link MultiFloatAction}.
-     */
-    public static final @ActionType int TYPE_MULTI_FLOAT = 3;
-
-    /**
      * The identifier of {@link ModeAction}.
      */
     public static final @ActionType int TYPE_MODE = 4;
@@ -121,28 +123,32 @@
     public static final @ResponseResult int RESPONSE_UNKNOWN = 0;
 
     /**
-     * Response code for {@link IControlsActionCallback#accept} indicating that
-     * the action has been performed. The action may still fail later and the state may not change.
+     * Response code for the {@code consumer} in
+     * {@link ControlsProviderService#performControlAction} indicating that the action has been
+     * performed. The action may still fail later and the state may not change.
      */
     public static final @ResponseResult int RESPONSE_OK = 1;
     /**
-     * Response code for {@link IControlsActionCallback#accept} indicating that
-     * the action has failed.
+     * Response code for the {@code consumer} in
+     * {@link ControlsProviderService#performControlAction} indicating that the action has failed.
      */
     public static final @ResponseResult int RESPONSE_FAIL = 2;
     /**
-     * Response code for {@link IControlsActionCallback#accept} indicating that
-     * in order for the action to be performed, acknowledgment from the user is required.
+     * Response code for the {@code consumer} in
+     * {@link ControlsProviderService#performControlAction} indicating that in order for the action
+     * to be performed, acknowledgment from the user is required.
      */
     public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3;
     /**
-     * Response code for {@link IControlsActionCallback#accept} indicating that
-     * in order for the action to be performed, a PIN is required.
+     * Response code for the {@code consumer} in
+     * {@link ControlsProviderService#performControlAction} indicating that in order for the action
+     * to be performed, a PIN is required.
      */
     public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 4;
     /**
-     * Response code for {@link IControlsActionCallback#accept} indicating that
-     * in order for the action to be performed, an alphanumeric passphrase is required.
+     * Response code for the {@code consumer} in
+     * {@link ControlsProviderService#performControlAction} indicating that in order for the action
+     * to be performed, an alphanumeric passphrase is required.
      */
     public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 5;
 
@@ -228,8 +234,6 @@
                     return new BooleanAction(bundle);
                 case TYPE_FLOAT:
                     return new FloatAction(bundle);
-                case TYPE_MULTI_FLOAT:
-                    return new MultiFloatAction(bundle);
                 case TYPE_MODE:
                     return new ModeAction(bundle);
                 case TYPE_COMMAND:
@@ -243,4 +247,12 @@
             return ERROR_ACTION;
         }
     }
+
+    /**
+     * Returns a singleton {@link ControlAction} used for indicating an error in unparceling.
+     */
+    @NonNull
+    public static ControlAction getErrorAction() {
+        return ERROR_ACTION;
+    }
 }
diff --git a/core/java/android/service/controls/actions/MultiFloatAction.java b/core/java/android/service/controls/actions/MultiFloatAction.java
deleted file mode 100644
index e574079..0000000
--- a/core/java/android/service/controls/actions/MultiFloatAction.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.controls.actions;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.internal.util.Preconditions;
-
-public final class MultiFloatAction extends ControlAction {
-
-    private static final String TAG = "MultiFloatAction";
-    private static final @ActionType int TYPE = TYPE_MULTI_FLOAT;
-    private static final String KEY_VALUES = "key_values";
-
-    private final @NonNull float[] mNewValues;
-
-    @Override
-    public int getActionType() {
-        return TYPE;
-    }
-
-    public MultiFloatAction(@NonNull String templateId,
-            @NonNull float[] newValues,
-            @Nullable String challengeValue) {
-        super(templateId, challengeValue);
-        Preconditions.checkNotNull(newValues);
-        if (newValues.length == 0) {
-            throw new IllegalArgumentException("newValues array length 0");
-        }
-        if (newValues.length == 1) {
-            Log.w(TAG, "newValues array length 1");
-        }
-        mNewValues = newValues.clone();
-    }
-
-    public MultiFloatAction(@NonNull String templateId, @NonNull float[] newValues) {
-        this(templateId, newValues, null);
-    }
-
-    /**
-     * @param b
-     * @hide
-     */
-    MultiFloatAction(Bundle b) {
-        super(b);
-        mNewValues = b.getFloatArray(KEY_VALUES);
-    }
-
-    @NonNull
-    public float[] getNewValues() {
-        return mNewValues.clone();
-    }
-
-    /**
-     * @return
-     * @hide
-     */
-    @Override
-    @NonNull
-    Bundle getDataBundle() {
-        Bundle b = super.getDataBundle();
-        b.putFloatArray(KEY_VALUES, mNewValues);
-        return b;
-    }
-}
diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java
index 30efd80..1e16273 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -49,18 +49,20 @@
 
     /**
      * Singleton representing a {@link Control} with no input.
+     * @hide
      */
     public static final @NonNull ControlTemplate NO_TEMPLATE = new ControlTemplate("") {
         @Override
         public int getTemplateType() {
-            return TYPE_NONE;
+            return TYPE_NO_TEMPLATE;
         }
     };
 
     /**
      * Object returned when there is an unparcelling error.
+     * @hide
      */
-    public static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") {
+    private static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") {
         @Override
         public int getTemplateType() {
             return TYPE_ERROR;
@@ -73,10 +75,9 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
             TYPE_ERROR,
-            TYPE_NONE,
+            TYPE_NO_TEMPLATE,
             TYPE_TOGGLE,
             TYPE_RANGE,
-            TYPE_THUMBNAIL,
             TYPE_TOGGLE_RANGE,
             TYPE_TEMPERATURE,
             TYPE_STATELESS
@@ -84,14 +85,14 @@
     public @interface TemplateType {}
 
     /**
-     * Type identifier of {@link #ERROR_TEMPLATE}.
+     * Type identifier of the template returned by {@link #getErrorTemplate()}.
      */
     public static final @TemplateType int TYPE_ERROR = -1;
 
     /**
-     * Type identifier of {@link ControlTemplate#NO_TEMPLATE}.
+     * Type identifier of {@link ControlTemplate#getNoTemplateObject}.
      */
-    public static final @TemplateType int TYPE_NONE = 0;
+    public static final @TemplateType int TYPE_NO_TEMPLATE = 0;
 
     /**
      * Type identifier of {@link ToggleTemplate}.
@@ -104,11 +105,6 @@
     public static final @TemplateType int TYPE_RANGE = 2;
 
     /**
-     * Type identifier of {@link ThumbnailTemplate}.
-     */
-    public static final @TemplateType int TYPE_THUMBNAIL = 3;
-
-    /**
      * Type identifier of {@link ToggleRangeTemplate}.
      */
     public static final @TemplateType int TYPE_TOGGLE_RANGE = 6;
@@ -191,15 +187,13 @@
                     return new ToggleTemplate(bundle);
                 case TYPE_RANGE:
                     return new RangeTemplate(bundle);
-                case TYPE_THUMBNAIL:
-                    return new ThumbnailTemplate(bundle);
                 case TYPE_TOGGLE_RANGE:
                     return new ToggleRangeTemplate(bundle);
                 case TYPE_TEMPERATURE:
                     return new TemperatureControlTemplate(bundle);
                 case TYPE_STATELESS:
                     return new StatelessTemplate(bundle);
-                case TYPE_NONE:
+                case TYPE_NO_TEMPLATE:
                     return NO_TEMPLATE;
                 case TYPE_ERROR:
                 default:
@@ -210,4 +204,27 @@
             return ERROR_TEMPLATE;
         }
     }
+
+    /**
+     * @return a singleton {@link ControlTemplate} used for indicating an error in unparceling.
+     */
+    @NonNull
+    public static ControlTemplate getErrorTemplate() {
+        return ERROR_TEMPLATE;
+    }
+
+    /**
+     * Get a singleton {@link ControlTemplate} that has no features.
+     *
+     * This template has no distinctive field, not even an identifier. Used for a {@link Control}
+     * that accepts no type of input, or when there is no known state.
+     *
+     * @return a singleton {@link ControlTemplate} to indicate no specific template is used by
+     *         this {@link Control}
+     */
+    @NonNull
+    public static ControlTemplate getNoTemplateObject() {
+        return NO_TEMPLATE;
+    }
+
 }
diff --git a/core/java/android/service/controls/templates/TemperatureControlTemplate.java b/core/java/android/service/controls/templates/TemperatureControlTemplate.java
index 0818c7e..96be97a 100644
--- a/core/java/android/service/controls/templates/TemperatureControlTemplate.java
+++ b/core/java/android/service/controls/templates/TemperatureControlTemplate.java
@@ -60,16 +60,34 @@
 
     private static final int NUM_MODES = 6;
 
+    /**
+     * Use when the current or active mode of the device is not known
+     */
     public static final @Mode int MODE_UNKNOWN = 0;
 
+    /**
+     * Indicates that the current or active mode of the device is off.
+     */
     public static final @Mode int MODE_OFF = 1;
 
+    /**
+     * Indicates that the current or active mode of the device is set to heat.
+     */
     public static final @Mode int MODE_HEAT = 2;
 
+    /**
+     * Indicates that the current or active mode of the device is set to cool.
+     */
     public static final @Mode int MODE_COOL = 3;
 
+    /**
+     * Indicates that the current or active mode of the device is set to heat-cool.
+     */
     public static final @Mode int MODE_HEAT_COOL = 4;
 
+    /**
+     * Indicates that the current or active mode of the device is set to eco.
+     */
     public static final @Mode int MODE_ECO = 5;
 
     /**
@@ -85,10 +103,29 @@
     })
     public @interface ModeFlag {}
 
+    /**
+     * Flag to indicate that the device supports off mode.
+     */
     public static final int FLAG_MODE_OFF = 1 << MODE_OFF;
+
+    /**
+     * Flag to indicate that the device supports heat mode.
+     */
     public static final int FLAG_MODE_HEAT = 1 << MODE_HEAT;
+
+    /**
+     * Flag to indicate that the device supports cool mode.
+     */
     public static final int FLAG_MODE_COOL = 1 << MODE_COOL;
+
+    /**
+     * Flag to indicate that the device supports heat-cool mode.
+     */
     public static final int FLAG_MODE_HEAT_COOL = 1 << MODE_HEAT_COOL;
+
+    /**
+     * Flag to indicate that the device supports eco mode.
+     */
     public static final int FLAG_MODE_ECO = 1 << MODE_ECO;
     private static final int ALL_FLAGS =
             FLAG_MODE_OFF |
diff --git a/core/java/android/service/controls/templates/ThumbnailTemplate.java b/core/java/android/service/controls/templates/ThumbnailTemplate.java
deleted file mode 100644
index 72179f4..0000000
--- a/core/java/android/service/controls/templates/ThumbnailTemplate.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.controls.templates;
-
-import android.annotation.NonNull;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.service.controls.Control;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * A template for a {@link Control} that displays an image.
- */
-public final class ThumbnailTemplate extends ControlTemplate {
-
-    private static final @TemplateType int TYPE = TYPE_THUMBNAIL;
-    private static final String KEY_ICON = "key_icon";
-    private static final String KEY_CONTENT_DESCRIPTION = "key_content_description";
-
-    private final @NonNull Icon mThumbnail;
-    private final @NonNull CharSequence mContentDescription;
-
-    /**
-     * @param templateId the identifier for this template object
-     * @param thumbnail an image to display on the {@link Control}
-     * @param contentDescription a description of the image for accessibility.
-     */
-    public ThumbnailTemplate(@NonNull String templateId, @NonNull Icon thumbnail,
-            @NonNull CharSequence contentDescription) {
-        super(templateId);
-        Preconditions.checkNotNull(thumbnail);
-        Preconditions.checkNotNull(contentDescription);
-        mThumbnail = thumbnail;
-        mContentDescription = contentDescription;
-    }
-
-    /**
-     * @param b
-     * @hide
-     */
-    ThumbnailTemplate(Bundle b) {
-        super(b);
-        mThumbnail = b.getParcelable(KEY_ICON);
-        mContentDescription = b.getCharSequence(KEY_CONTENT_DESCRIPTION, "");
-    }
-
-    /**
-     * The {@link Icon} (image) displayed by this template.
-     */
-    @NonNull
-    public Icon getThumbnail() {
-        return mThumbnail;
-    }
-
-    /**
-     * The description of the image returned by {@link ThumbnailTemplate#getThumbnail()}
-     */
-    @NonNull
-    public CharSequence getContentDescription() {
-        return mContentDescription;
-    }
-
-    /**
-     * @return {@link ControlTemplate#TYPE_THUMBNAIL}
-     */
-    @Override
-    public int getTemplateType() {
-        return TYPE;
-    }
-
-    /**
-     * @return
-     * @hide
-     */
-    @Override
-    @NonNull
-    Bundle getDataBundle() {
-        Bundle b = super.getDataBundle();
-        b.putObject(KEY_ICON, mThumbnail);
-        b.putObject(KEY_CONTENT_DESCRIPTION, mContentDescription);
-        return b;
-    }
-}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index cfbe393..6b87a10 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -71,7 +71,7 @@
         // introduced in R and will be removed in the next release (b/148367230).
         DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "false");
 
-        DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
+        DEFAULT_FLAGS.put("settings_tether_all_in_one", "true");
         DEFAULT_FLAGS.put(SETTINGS_SCHEDULES_FLAG, "false");
         DEFAULT_FLAGS.put("settings_contextual_home2", "false");
     }
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 92ac425..f07f1ce 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -87,6 +87,7 @@
         if (mSourceControl == control) {
             return;
         }
+        final InsetsSourceControl lastControl = mSourceControl;
         mSourceControl = control;
 
         // We are loosing control
@@ -97,25 +98,27 @@
             mState.getSource(getType()).setVisible(
                     mController.getLastDispatchedState().getSource(getType()).isVisible());
             applyLocalVisibilityOverride();
-            return;
-        }
-
-        // We are gaining control, and need to run an animation since previous state didn't match
-        if (mRequestedVisible != mState.getSource(mType).isVisible()) {
-            if (mRequestedVisible) {
-                showTypes[0] |= toPublicType(getType());
+        } else {
+            // We are gaining control, and need to run an animation since previous state
+            // didn't match
+            if (mRequestedVisible != mState.getSource(mType).isVisible()) {
+                if (mRequestedVisible) {
+                    showTypes[0] |= toPublicType(getType());
+                } else {
+                    hideTypes[0] |= toPublicType(getType());
+                }
             } else {
-                hideTypes[0] |= toPublicType(getType());
+              // We are gaining control, but don't need to run an animation.
+              // However make sure that the leash visibility is still up to date.
+              if (applyLocalVisibilityOverride()) {
+                  mController.notifyVisibilityChanged();
+              }
+              applyHiddenToControl();
             }
-            return;
         }
-
-        // We are gaining control, but don't need to run an animation. However make sure that the
-        // leash visibility is still up to date.
-        if (applyLocalVisibilityOverride()) {
-            mController.notifyVisibilityChanged();
+        if (lastControl != null) {
+            lastControl.release();
         }
-        applyHiddenToControl();
     }
 
     @VisibleForTesting
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 7be3e6a..29ba56a 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -94,6 +94,12 @@
         dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
     }
 
+    public void release() {
+        if (mLeash != null) {
+            mLeash.release();
+        }
+    }
+
     public static final @android.annotation.NonNull Creator<InsetsSourceControl> CREATOR
             = new Creator<InsetsSourceControl>() {
         public InsetsSourceControl createFromParcel(Parcel in) {
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index f406be9..e05c374 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -72,6 +72,33 @@
     }
 
     /**
+     * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an
+     * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
+     * the full bounds.
+     */
+    public WindowContainerTransaction setAppBounds(IWindowContainer container, Rect appBounds) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+        chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+        return this;
+    }
+
+    /**
+     * Resize a container's configuration size. The configuration size is what gets reported to the
+     * app via screenWidth/HeightDp and influences which resources get loaded. This size is
+     * derived by subtracting the overlapping portions of both the statusbar and the navbar from
+     * the full bounds.
+     */
+    public WindowContainerTransaction setScreenSizeDp(IWindowContainer container, int w, int h) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.screenWidthDp = w;
+        chg.mConfiguration.screenHeightDp = h;
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE;
+        return this;
+    }
+
+    /**
      * Notify activies within the hiearchy of a container that they have entered picture-in-picture
      * mode with the given bounds.
      */
@@ -161,7 +188,8 @@
 
     @Override
     public String toString() {
-        return "WindowContainerTransaction { changes = " + mChanges + " }";
+        return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
+                + " }";
     }
 
     @Override
@@ -269,6 +297,11 @@
                     (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
                             && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
                                     != 0);
+            final boolean changesAppBounds =
+                    (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
+                            && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS)
+                                    != 0);
+            final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0;
             final boolean changesSss =
                     (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
             StringBuilder sb = new StringBuilder();
@@ -276,9 +309,16 @@
             if (changesBounds) {
                 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
             }
+            if (changesAppBounds) {
+                sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ",");
+            }
             if (changesSss) {
                 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
             }
+            if (changesSs) {
+                sb.append("sw/h:" + mConfiguration.screenWidthDp + "x"
+                        + mConfiguration.screenHeightDp + ",");
+            }
             if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
                 sb.append("focusable:" + mFocusable + ",");
             }
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index bcf731d..d50826f 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -299,11 +299,8 @@
                     .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
                     .setStrings(getMetricsCategory())
                     .write();
-            showEmptyState(activeListAdapter,
-                    R.drawable.ic_work_apps_off,
-                    R.string.resolver_turn_on_work_apps,
-                    R.string.resolver_turn_on_work_apps_explanation,
-                    (View.OnClickListener) v -> {
+            showWorkProfileOffEmptyState(activeListAdapter,
+                    v -> {
                         ProfileDescriptor descriptor = getItem(
                                 userHandleToPageIndex(activeListAdapter.getUserHandle()));
                         showSpinner(descriptor.getEmptyStateView());
@@ -319,27 +316,29 @@
                                 DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
                             .setStrings(getMetricsCategory())
                             .write();
-                    showEmptyState(activeListAdapter,
-                            R.drawable.ic_sharing_disabled,
-                            R.string.resolver_cant_share_with_personal_apps,
-                            R.string.resolver_cant_share_cross_profile_explanation);
+                    showNoWorkToPersonalIntentsEmptyState(activeListAdapter);
                 } else {
                     DevicePolicyEventLogger.createEvent(
                             DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK)
                             .setStrings(getMetricsCategory())
                             .write();
-                    showEmptyState(activeListAdapter,
-                            R.drawable.ic_sharing_disabled,
-                            R.string.resolver_cant_share_with_work_apps,
-                            R.string.resolver_cant_share_cross_profile_explanation);
+                    showNoPersonalToWorkIntentsEmptyState(activeListAdapter);
                 }
                 return false;
             }
         }
-        showListView(activeListAdapter);
         return activeListAdapter.rebuildList(doPostProcessing);
     }
 
+    protected abstract void showWorkProfileOffEmptyState(
+            ResolverListAdapter activeListAdapter, View.OnClickListener listener);
+
+    protected abstract void showNoPersonalToWorkIntentsEmptyState(
+            ResolverListAdapter activeListAdapter);
+
+    protected abstract void showNoWorkToPersonalIntentsEmptyState(
+            ResolverListAdapter activeListAdapter);
+
     void showEmptyState(ResolverListAdapter listAdapter) {
         UserHandle listUserHandle = listAdapter.getUserHandle();
         if (UserHandle.myUserId() == listUserHandle.getIdentifier()
@@ -353,16 +352,16 @@
             showEmptyState(listAdapter,
                     R.drawable.ic_no_apps,
                     R.string.resolver_no_apps_available,
-                    R.string.resolver_no_apps_available_explanation);
+                    /* subtitleRes */ 0);
         }
     }
 
-    private void showEmptyState(ResolverListAdapter activeListAdapter,
+    protected void showEmptyState(ResolverListAdapter activeListAdapter,
             @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes) {
         showEmptyState(activeListAdapter, iconRes, titleRes, subtitleRes, /* buttonOnClick */ null);
     }
 
-    private void showEmptyState(ResolverListAdapter activeListAdapter,
+    protected void showEmptyState(ResolverListAdapter activeListAdapter,
             @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes,
             View.OnClickListener buttonOnClick) {
         ProfileDescriptor descriptor = getItem(
@@ -379,11 +378,18 @@
         title.setText(titleRes);
 
         TextView subtitle = emptyStateView.findViewById(R.id.resolver_empty_state_subtitle);
-        subtitle.setText(subtitleRes);
+        if (subtitleRes != 0) {
+            subtitle.setVisibility(View.VISIBLE);
+            subtitle.setText(subtitleRes);
+        } else {
+            subtitle.setVisibility(View.GONE);
+        }
 
         Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button);
         button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
         button.setOnClickListener(buttonOnClick);
+
+        activeListAdapter.markTabLoaded();
     }
 
     private void showSpinner(View emptyStateView) {
@@ -403,7 +409,7 @@
         emptyStateView.findViewById(R.id.resolver_empty_state_progress).setVisibility(View.GONE);
     }
 
-    private void showListView(ResolverListAdapter activeListAdapter) {
+    protected void showListView(ResolverListAdapter activeListAdapter) {
         ProfileDescriptor descriptor = getItem(
                 userHandleToPageIndex(activeListAdapter.getUserHandle()));
         descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.VISIBLE);
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index b39d42ec..2167b1e 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.internal.R;
@@ -169,6 +170,32 @@
         return ResolverActivity.METRICS_CATEGORY_CHOOSER;
     }
 
+    @Override
+    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
+            View.OnClickListener listener) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_work_apps_off,
+                R.string.resolver_turn_on_work_apps_share,
+                /* subtitleRes */ 0,
+                listener);
+    }
+
+    @Override
+    protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_share_with_work_apps,
+                R.string.resolver_cant_share_cross_profile_explanation);
+    }
+
+    @Override
+    protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_share_with_personal_apps,
+                R.string.resolver_cant_share_cross_profile_explanation);
+    }
+
     class ChooserProfileDescriptor extends ProfileDescriptor {
         private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
         private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f745e43..ec371d9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -163,7 +163,7 @@
      * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
      */
     @VisibleForTesting
-    public static boolean ENABLE_TABBED_VIEW = false;
+    public static boolean ENABLE_TABBED_VIEW = true;
     private static final String TAB_TAG_PERSONAL = "personal";
     private static final String TAB_TAG_WORK = "work";
 
@@ -854,6 +854,11 @@
 
     private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
             boolean filtered) {
+        if (mMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
+            // Never allow the inactive profile to always open an app.
+            mAlwaysButton.setEnabled(false);
+            return;
+        }
         boolean enabled = false;
         ResolveInfo ri = null;
         if (hasValidSelection) {
@@ -877,19 +882,21 @@
             }
         }
 
-        ActivityInfo activityInfo = ri.activityInfo;
+        if (ri != null) {
+            ActivityInfo activityInfo = ri.activityInfo;
 
-        boolean hasRecordPermission =
-                mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO,
-                        activityInfo.packageName)
-                    == android.content.pm.PackageManager.PERMISSION_GRANTED;
+            boolean hasRecordPermission =
+                    mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO,
+                            activityInfo.packageName)
+                            == android.content.pm.PackageManager.PERMISSION_GRANTED;
 
-        if (!hasRecordPermission) {
-            // OK, we know the record permission, is this a capture device
-            boolean hasAudioCapture =
-                    getIntent().getBooleanExtra(
-                            ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
-            enabled = !hasAudioCapture;
+            if (!hasRecordPermission) {
+                // OK, we know the record permission, is this a capture device
+                boolean hasAudioCapture =
+                        getIntent().getBooleanExtra(
+                                ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
+                enabled = !hasAudioCapture;
+            }
         }
         mAlwaysButton.setEnabled(enabled);
     }
@@ -982,6 +989,8 @@
         }
         if (shouldShowEmptyState(listAdapter)) {
             mMultiProfilePagerAdapter.showEmptyState(listAdapter);
+        } else {
+            mMultiProfilePagerAdapter.showListView(listAdapter);
         }
         if (doPostProcessing) {
             if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
@@ -1330,9 +1339,12 @@
                     + "cannot be null.");
         }
         // We partially rebuild the inactive adapter to determine if we should auto launch
-        boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true);
+        // isTabLoaded will be true here if the empty state screen is shown instead of the list.
+        boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true)
+                || mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded();
         if (shouldShowTabs()) {
-            boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false);
+            boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false)
+                    || mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded();
             rebuildCompleted = rebuildCompleted && rebuildInactiveCompleted;
         }
 
@@ -1392,8 +1404,8 @@
         if (numberOfProfiles == 1 && maybeAutolaunchIfSingleTarget()) {
             return true;
         } else if (numberOfProfiles == 2
-                && mMultiProfilePagerAdapter.getActiveListAdapter().isListLoaded()
-                && mMultiProfilePagerAdapter.getInactiveListAdapter().isListLoaded()
+                && mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded()
+                && mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded()
                 && (maybeAutolaunchIfNoAppsOnInactiveTab()
                         || maybeAutolaunchIfCrossProfileSupported())) {
             return true;
@@ -1567,14 +1579,38 @@
 
         viewPager.setVisibility(View.VISIBLE);
         tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
-        mMultiProfilePagerAdapter.setOnProfileSelectedListener(tabHost::setCurrentTab);
+        mMultiProfilePagerAdapter.setOnProfileSelectedListener(
+                index -> {
+                    tabHost.setCurrentTab(index);
+                    resetButtonBar();
+                    resetCheckedItem();
+                });
         findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
     }
 
+    private void resetCheckedItem() {
+        if (!isIntentPicker()) {
+            return;
+        }
+        mLastSelected = ListView.INVALID_POSITION;
+        ListView inactiveListView = (ListView) mMultiProfilePagerAdapter.getInactiveAdapterView();
+        if (inactiveListView.getCheckedItemCount() > 0) {
+            inactiveListView.setItemChecked(inactiveListView.getCheckedItemPosition(), false);
+        }
+    }
+
     private void resetTabsHeaderStyle(TabWidget tabWidget) {
+        String workContentDescription = getString(R.string.resolver_work_tab_accessibility);
+        String personalContentDescription = getString(R.string.resolver_personal_tab_accessibility);
         for (int i = 0; i < tabWidget.getChildCount(); i++) {
-            TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title);
+            View tabView = tabWidget.getChildAt(i);
+            TextView title = tabView.findViewById(android.R.id.title);
             title.setTextColor(getColor(R.color.resolver_tabs_inactive_color));
+            if (title.getText().equals(getString(R.string.resolver_personal_tab))) {
+                tabView.setContentDescription(personalContentDescription);
+            } else if (title.getText().equals(getString(R.string.resolver_work_tab))) {
+                tabView.setContentDescription(workContentDescription);
+            }
         }
     }
 
@@ -1677,6 +1713,10 @@
     }
 
     private void resetAlwaysOrOnceButtonBar() {
+        // Disable both buttons initially
+        setAlwaysButtonEnabled(false, ListView.INVALID_POSITION, false);
+        mOnceButton.setEnabled(false);
+
         int filteredPosition = mMultiProfilePagerAdapter.getActiveListAdapter()
                 .getFilteredPosition();
         if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) {
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 54453d0..61a404e 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -87,7 +87,7 @@
     private final ResolverListCommunicator mResolverListCommunicator;
     private Runnable mPostListReadyRunnable;
     private final boolean mIsAudioCaptureDevice;
-    private boolean mIsListLoaded;
+    private boolean mIsTabLoaded;
 
     public ResolverListAdapter(Context context, List<Intent> payloadIntents,
             Intent[] initialIntents, List<ResolveInfo> rList,
@@ -192,7 +192,7 @@
         mLastChosenPosition = -1;
         mAllTargetsAreBrowsers = false;
         mDisplayList.clear();
-        mIsListLoaded = false;
+        mIsTabLoaded = false;
 
         if (mBaseResolveList != null) {
             currentResolveList = mUnfilteredResolveList = new ArrayList<>();
@@ -354,7 +354,7 @@
 
         mResolverListCommunicator.sendVoiceChoicesIfNeeded();
         postListReadyRunnable(doPostProcessing);
-        mIsListLoaded = true;
+        mIsTabLoaded = true;
     }
 
     /**
@@ -614,8 +614,12 @@
         return mIntents;
     }
 
-    protected boolean isListLoaded() {
-        return mIsListLoaded;
+    protected boolean isTabLoaded() {
+        return mIsTabLoaded;
+    }
+
+    protected void markTabLoaded() {
+        mIsTabLoaded = true;
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index f6382d3..0440f5e 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ListView;
 
@@ -161,6 +162,32 @@
         return ResolverActivity.METRICS_CATEGORY_RESOLVER;
     }
 
+    @Override
+    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
+            View.OnClickListener listener) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_work_apps_off,
+                R.string.resolver_turn_on_work_apps_view,
+                /* subtitleRes */ 0,
+                listener);
+    }
+
+    @Override
+    protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_access_work_apps,
+                R.string.resolver_cant_access_work_apps_explanation);
+    }
+
+    @Override
+    protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_access_personal_apps,
+                R.string.resolver_cant_access_personal_apps_explanation);
+    }
+
     class ResolverProfileDescriptor extends ProfileDescriptor {
         private ResolverListAdapter resolverListAdapter;
         final ListView listView;
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
index 16628d7..ab890d2 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
@@ -30,6 +30,7 @@
     private final @Nullable String mName;
     private final int mEnableAfterTargetSdk;
     private final boolean mDisabled;
+    private final boolean mLoggingOnly;
     private final @Nullable String mDescription;
 
     public long getId() {
@@ -49,17 +50,22 @@
         return mDisabled;
     }
 
+    public boolean getLoggingOnly() {
+        return mLoggingOnly;
+    }
+
     public String getDescription()  {
         return mDescription;
     }
 
     public CompatibilityChangeInfo(
             Long changeId, String name, int enableAfterTargetSdk, boolean disabled,
-            String description) {
+            boolean loggingOnly, String description) {
         this.mChangeId = changeId;
         this.mName = name;
         this.mEnableAfterTargetSdk = enableAfterTargetSdk;
         this.mDisabled = disabled;
+        this.mLoggingOnly = loggingOnly;
         this.mDescription = description;
     }
 
@@ -68,6 +74,7 @@
         mName = in.readString();
         mEnableAfterTargetSdk = in.readInt();
         mDisabled = in.readBoolean();
+        mLoggingOnly = in.readBoolean();
         mDescription = in.readString();
     }
 
@@ -82,6 +89,7 @@
         dest.writeString(mName);
         dest.writeInt(mEnableAfterTargetSdk);
         dest.writeBoolean(mDisabled);
+        dest.writeBoolean(mLoggingOnly);
         dest.writeString(mDescription);
     }
 
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index 56216c2..bed41b3 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -33,7 +33,8 @@
             DISABLED_NOT_DEBUGGABLE,
             DISABLED_NON_TARGET_SDK,
             DISABLED_TARGET_SDK_TOO_HIGH,
-            PACKAGE_DOES_NOT_EXIST
+            PACKAGE_DOES_NOT_EXIST,
+            LOGGING_ONLY_CHANGE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface State {
@@ -60,6 +61,10 @@
      * Package does not exist.
      */
     public static final int PACKAGE_DOES_NOT_EXIST = 4;
+    /**
+     * Change is marked as logging only, and cannot be toggled.
+     */
+    public static final int LOGGING_ONLY_CHANGE = 5;
 
     @State
     public final int state;
@@ -118,6 +123,10 @@
                         "Cannot override %1$d for %2$s because the package does not exist, and "
                                 + "the change is targetSdk gated.",
                         changeId, packageName));
+            case LOGGING_ONLY_CHANGE:
+                throw new SecurityException(String.format(
+                        "Cannot override %1$d because it is marked as a logging-only change.",
+                        changeId));
         }
     }
 
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 6d2d735..7dc3871 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -232,7 +232,7 @@
                 .append(", allowIPv4=").append(allowIPv4)
                 .append(", allowIPv6=").append(allowIPv6)
                 .append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
-                .append(", proxyInfo=").append(proxyInfo.toString())
+                .append(", proxyInfo=").append(proxyInfo)
                 .append("}")
                 .toString();
     }
diff --git a/core/java/com/android/internal/util/DataClass.java b/core/java/com/android/internal/util/DataClass.java
index 43539c7..ee139d9 100644
--- a/core/java/com/android/internal/util/DataClass.java
+++ b/core/java/com/android/internal/util/DataClass.java
@@ -15,7 +15,13 @@
  */
 package com.android.internal.util;
 
-import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
@@ -243,6 +249,13 @@
     }
 
     /**
+     * Mark that the field should have a {@link Nullable} argument for its setter.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({FIELD})
+    @interface MaySetToNull {}
+
+    /**
      * Callback used by {@link #genForEachField}.
      *
      * @param <THIS> The enclosing data class instance.
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index b117e40..c83cab7 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -121,7 +121,8 @@
 
     private final Rect mTempRect = new Rect();
 
-    private AbsListView mNestedScrollingChild;
+    private AbsListView mNestedListChild;
+    private RecyclerView mNestedRecyclerChild;
 
     private final ViewTreeObserver.OnTouchModeChangeListener mTouchModeChangeListener =
             new ViewTreeObserver.OnTouchModeChangeListener() {
@@ -347,11 +348,20 @@
         return mIsDragging || mOpenOnClick;
     }
 
-    private boolean isNestedChildScrolled() {
-        return mNestedScrollingChild != null
-                && mNestedScrollingChild.getChildCount() > 0
-                && (mNestedScrollingChild.getFirstVisiblePosition() > 0
-                        || mNestedScrollingChild.getChildAt(0).getTop() < 0);
+    private boolean isNestedListChildScrolled() {
+        return  mNestedListChild != null
+                && mNestedListChild.getChildCount() > 0
+                && (mNestedListChild.getFirstVisiblePosition() > 0
+                        || mNestedListChild.getChildAt(0).getTop() < 0);
+    }
+
+    private boolean isNestedRecyclerChildScrolled() {
+        if (mNestedRecyclerChild != null && mNestedRecyclerChild.getChildCount() > 0) {
+            final RecyclerView.ViewHolder vh =
+                    mNestedRecyclerChild.findViewHolderForAdapterPosition(0);
+            return vh == null || vh.itemView.getTop() < 0;
+        }
+        return false;
     }
 
     @Override
@@ -396,8 +406,10 @@
                 }
                 if (mIsDragging) {
                     final float dy = y - mLastTouchY;
-                    if (dy > 0 && isNestedChildScrolled()) {
-                        mNestedScrollingChild.smoothScrollBy((int) -dy, 0);
+                    if (dy > 0 && isNestedListChildScrolled()) {
+                        mNestedListChild.smoothScrollBy((int) -dy, 0);
+                    } else if (dy > 0 && isNestedRecyclerChildScrolled()) {
+                        mNestedRecyclerChild.scrollBy(0, (int) -dy);
                     } else {
                         performDrag(dy);
                     }
@@ -452,8 +464,10 @@
                             smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
                             mDismissOnScrollerFinished = true;
                         } else {
-                            if (isNestedChildScrolled()) {
-                                mNestedScrollingChild.smoothScrollToPosition(0);
+                            if (isNestedListChildScrolled()) {
+                                mNestedListChild.smoothScrollToPosition(0);
+                            } else if (isNestedRecyclerChildScrolled()) {
+                                mNestedRecyclerChild.smoothScrollToPosition(0);
                             }
                             smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
                         }
@@ -729,8 +743,11 @@
     @Override
     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
         if ((nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0) {
-            if (child instanceof AbsListView) {
-                mNestedScrollingChild = (AbsListView) child;
+            if (target instanceof AbsListView) {
+                mNestedListChild = (AbsListView) target;
+            }
+            if (target instanceof RecyclerView) {
+                mNestedRecyclerChild = (RecyclerView) target;
             }
             return true;
         }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ade2c7d..189a0a7 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,13 +1,4 @@
 
-genrule {
-    name: "android_util_StatsLogInternal.cpp",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLogInternal.cpp",
-    out: [
-        "android_util_StatsLogInternal.cpp",
-    ],
-}
-
 cc_library_shared {
     name: "libandroid_runtime",
     host_supported: true,
@@ -149,6 +140,7 @@
                 "android_media_AudioEffectDescriptor.cpp",
                 "android_media_AudioRecord.cpp",
                 "android_media_AudioSystem.cpp",
+                "android_media_AudioTrackCallback.cpp",
                 "android_media_AudioTrack.cpp",
                 "android_media_AudioAttributes.cpp",
                 "android_media_AudioProductStrategies.cpp",
@@ -277,7 +269,6 @@
                 // our headers include libnativewindow's public headers
                 "libnativewindow",
             ],
-            generated_sources: ["android_util_StatsLogInternal.cpp"],
             header_libs: ["bionic_libc_platform_headers"],
         },
         host: {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c41398c..ba7aef7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -108,7 +108,6 @@
 extern int register_android_app_admin_SecurityLog(JNIEnv* env);
 extern int register_android_content_AssetManager(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
-extern int register_android_util_StatsLogInternal(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_MemoryIntArray(JNIEnv* env);
 extern int register_android_content_StringBlock(JNIEnv* env);
@@ -1435,7 +1434,6 @@
         REG_JNI(register_android_util_EventLog),
         REG_JNI(register_android_util_Log),
         REG_JNI(register_android_util_MemoryIntArray),
-        REG_JNI(register_android_util_StatsLogInternal),
         REG_JNI(register_android_app_admin_SecurityLog),
         REG_JNI(register_android_content_AssetManager),
         REG_JNI(register_android_content_StringBlock),
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a888b43..1351818 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -31,13 +31,14 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
 
-#include "android_media_AudioFormat.h"
+#include "android_media_AudioAttributes.h"
 #include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
+#include "android_media_AudioTrackCallback.h"
+#include "android_media_DeviceCallback.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_PlaybackParams.h"
-#include "android_media_DeviceCallback.h"
 #include "android_media_VolumeShaper.h"
-#include "android_media_AudioAttributes.h"
 
 #include <cinttypes>
 
@@ -75,22 +76,12 @@
 
 // ----------------------------------------------------------------------------
 class AudioTrackJniStorage {
-    public:
-        sp<MemoryHeapBase>         mMemHeap;
-        sp<MemoryBase>             mMemBase;
-        audiotrack_callback_cookie mCallbackData;
-        sp<JNIDeviceCallback>      mDeviceCallback;
-
-    AudioTrackJniStorage() {
-        mCallbackData.audioTrack_class = 0;
-        mCallbackData.audioTrack_ref = 0;
-        mCallbackData.isOffload = false;
-    }
-
-    ~AudioTrackJniStorage() {
-        mMemBase.clear();
-        mMemHeap.clear();
-    }
+public:
+    sp<MemoryHeapBase> mMemHeap;
+    sp<MemoryBase> mMemBase;
+    audiotrack_callback_cookie mCallbackData{};
+    sp<JNIDeviceCallback> mDeviceCallback;
+    sp<JNIAudioTrackCallback> mAudioTrackCallback;
 
     bool allocSharedMem(int sizeInBytes) {
         mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
@@ -459,6 +450,10 @@
         lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
         lpJniStorage->mCallbackData.busy = false;
     }
+    lpJniStorage->mAudioTrackCallback =
+            new JNIAudioTrackCallback(env, thiz, lpJniStorage->mCallbackData.audioTrack_ref,
+                                      javaAudioTrackFields.postNativeEventInJava);
+    lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
 
     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
diff --git a/core/jni/android_media_AudioTrackCallback.cpp b/core/jni/android_media_AudioTrackCallback.cpp
new file mode 100644
index 0000000..d97566b
--- /dev/null
+++ b/core/jni/android_media_AudioTrackCallback.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioTrackCallback-JNI"
+
+#include <algorithm>
+
+#include <nativehelper/JNIHelp.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "android_media_AudioTrackCallback.h"
+#include "core_jni_helpers.h"
+
+using namespace android;
+
+#define BYTE_BUFFER_NAME "java/nio/ByteBuffer"
+#define BYTE_BUFFER_ALLOCATE_DIRECT_NAME "allocateDirect"
+
+JNIAudioTrackCallback::JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
+                                             jmethodID postEventFromNative) {
+    // Hold onto the AudioTrack class for use in calling the static method
+    // that posts events to the application thread.
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == nullptr) {
+        return;
+    }
+    mClass = (jclass)env->NewGlobalRef(clazz);
+
+    // We use a weak reference so the AudioTrack object can be garbage collected.
+    // The reference is only used as a proxy for callbacks.
+    mObject = env->NewGlobalRef(weak_thiz);
+
+    mPostEventFromNative = postEventFromNative;
+
+    jclass byteBufferClass = FindClassOrDie(env, BYTE_BUFFER_NAME);
+    mByteBufferClass = (jclass)env->NewGlobalRef(byteBufferClass);
+    mAllocateDirectMethod =
+            GetStaticMethodIDOrDie(env, mByteBufferClass, BYTE_BUFFER_ALLOCATE_DIRECT_NAME,
+                                   "(I)Ljava/nio/ByteBuffer;");
+}
+
+JNIAudioTrackCallback::~JNIAudioTrackCallback() {
+    // remove global references
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (env == nullptr) {
+        return;
+    }
+    env->DeleteGlobalRef(mObject);
+    env->DeleteGlobalRef(mClass);
+    env->DeleteGlobalRef(mByteBufferClass);
+}
+
+binder::Status JNIAudioTrackCallback::onCodecFormatChanged(
+        const std::vector<uint8_t>& audioMetadata) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (env == nullptr) {
+        return binder::Status::ok();
+    }
+
+    jobject byteBuffer = env->CallStaticObjectMethod(mByteBufferClass, mAllocateDirectMethod,
+                                                     (jint)audioMetadata.size());
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred while allocating direct buffer");
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+    if (byteBuffer == nullptr) {
+        ALOGE("Failed allocating a direct ByteBuffer");
+        return binder::Status::fromStatusT(NO_MEMORY);
+    }
+
+    uint8_t* byteBufferAddr = (uint8_t*)env->GetDirectBufferAddress(byteBuffer);
+    std::copy(audioMetadata.begin(), audioMetadata.end(), byteBufferAddr);
+    env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject,
+                              AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE, 0, 0, byteBuffer);
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred while notifying codec format changed.");
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+
+    return binder::Status::ok();
+}
diff --git a/core/jni/android_media_AudioTrackCallback.h b/core/jni/android_media_AudioTrackCallback.h
new file mode 100644
index 0000000..3b8a8bb
--- /dev/null
+++ b/core/jni/android_media_AudioTrackCallback.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
+#define ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
+
+#include <android/media/BnAudioTrackCallback.h>
+
+namespace android {
+
+#define AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE 100
+
+// TODO(b/149870866) : Extract common part for JNIAudioTrackCallback and JNIDeviceCallback
+class JNIAudioTrackCallback : public media::BnAudioTrackCallback {
+public:
+    JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
+                          jmethodID postEventFromNative);
+    ~JNIAudioTrackCallback() override;
+
+    binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+private:
+    jclass mClass;                   // Reference to AudioTrack class
+    jobject mObject;                 // Weak ref to AudioTrack Java object to call on
+    jmethodID mPostEventFromNative;  // postEventFromNative method ID
+    jclass mByteBufferClass;         // Reference to ByteBuffer class
+    jmethodID mAllocateDirectMethod; // ByteBuffer.allocateDirect method ID
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index cfd3c09..c72668f 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,7 +33,6 @@
 
 // Static whitelist of open paths that the zygote is allowed to keep open.
 static const char* kPathWhitelist[] = {
-        "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
         "/apex/com.android.conscrypt/javalib/conscrypt.jar",
         "/apex/com.android.ipsec/javalib/ike.jar",
         "/apex/com.android.media/javalib/updatable-media.jar",
diff --git a/core/proto/android/app/appexit_enums.proto b/core/proto/android/app/appexit_enums.proto
new file mode 100644
index 0000000..491e1dc
--- /dev/null
+++ b/core/proto/android/app/appexit_enums.proto
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * The reason code that why app process is killed.
+ */
+enum AppExitReasonCode {
+    /**
+     * Application process died due to unknown reason.
+     */
+    REASON_UNKNOWN = 0;
+
+    /**
+     * Application process exit normally by itself, for example,
+     * via {@link android.os.Process#exit}; {@link #status} will specify the exit code.
+     *
+     * <p>Applications should normally not do this, as the system has a better knowledge
+     * in terms of process management.</p>
+     */
+    REASON_EXIT_SELF = 1;
+
+    /**
+     * Application process died due to the result of an OS signal; for example,
+     * {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum.
+     */
+    REASON_SIGNALED = 2;
+
+    /**
+     * Application process was killed by the system low memory killer, meaning the system was
+     * under memory pressure at the time of kill.
+     */
+    REASON_LOW_MEMORY = 3;
+
+    /**
+     * Application process died because of an unhandled exception in Java code.
+     */
+    REASON_CRASH = 4;
+
+    /**
+     * Application process died because it's crashed due to a native code crash.
+     */
+    REASON_CRASH_NATIVE = 5;
+
+    /**
+     * Application process was killed due to being unresponsive (ANR).
+     */
+    REASON_ANR = 6;
+
+    /**
+     * Application process was killed because it took too long to attach to the system
+     * during the start.
+     */
+    REASON_INITIALIZATION_FAILURE = 7;
+
+    /**
+     * Application process was killed because of initialization failure,
+     * for example, it took too long to attach to the system during the start,
+     * or there was an error during initialization.
+     */
+    REASON_PERMISSION_CHANGE = 8;
+
+    /**
+     * Application process was killed by the activity manager due to excessive resource usage.
+     */
+    REASON_EXCESSIVE_RESOURCE_USAGE = 9;
+
+    /**
+     * Application process was killed because of the user request, for example,
+     * user clicked the "Force stop" button of the application in the Settings,
+     * or swiped away the application from Recents.
+     */
+    REASON_USER_REQUESTED = 10;
+
+    /**
+     * Application process was killed, because the user they are running as on devices
+     * with mutlple users, was stopped.
+     */
+    REASON_USER_STOPPED = 11;
+
+    /**
+     * Application process was killed because its dependency was going away, for example,
+     * a stable content provider connection's client will be killed if the provider is killed.
+     */
+    REASON_DEPENDENCY_DIED = 12;
+
+    /**
+     * Application process was killed by the system for various other reasons,
+     * for example, the application package got disabled by the user;
+     * {@link #description} will specify the cause given by the system.
+     */
+    REASON_OTHER = 13;
+}
+
+/**
+ * The supplemental reason code that why app process is killed
+ */
+enum AppExitSubReasonCode {
+    /**
+     * Application process kills subReason is unknown.
+     */
+    SUBREASON_UNKNOWN = 0;
+
+    /**
+     * Application process was killed because user quit it on the "wait for debugger" dialog.
+     */
+    SUBREASON_WAIT_FOR_DEBUGGER = 1;
+
+    /**
+     * Application process was killed by the activity manager because there were too many cached
+     * processes.
+     */
+    SUBREASON_TOO_MANY_CACHED = 2;
+
+    /**
+     * Application process was killed by the activity manager because there were too many empty
+     * processes.
+     */
+    SUBREASON_TOO_MANY_EMPTY = 3;
+
+    /**
+     * Application process was killed by the activity manager because there were too many cached
+     * processes and this process had been in empty state for a long time.
+     */
+    SUBREASON_TRIM_EMPTY = 4;
+
+    /**
+     * Application process was killed by the activity manager because system was on
+     * memory pressure and this process took large amount of cached memory.
+     */
+    SUBREASON_LARGE_CACHED = 5;
+
+    /**
+     * Application process was killed by the activity manager because the system was on
+     * low memory pressure for a significant amount of time since last idle.
+     */
+    SUBREASON_MEMORY_PRESSURE = 6;
+
+    /**
+     * Application process was killed by the activity manager due to excessive CPU usage.
+     */
+    SUBREASON_EXCESSIVE_CPU = 7;
+
+    /**
+     * System update has done (so the system update process should be killed).
+     */
+    SUBREASON_SYSTEM_UPDATE_DONE = 8;
+
+    /**
+     * Kill all foreground services, for now it only occurs when enabling the quiet
+     * mode for the managed profile.
+     */
+    SUBREASON_KILL_ALL_FG = 9;
+
+    /**
+     * All background processes except certain ones were killed, for now it only occurs
+     * when the density of the default display is changed.
+     */
+    SUBREASON_KILL_ALL_BG_EXCEPT = 10;
+
+    /**
+     * The process associated with the UID was explicitly killed, for example,
+     * it could be because of permission changes.
+     */
+    SUBREASON_KILL_UID = 11;
+
+    /**
+     * The process was explicitly killed with its PID, typically because of
+     * the low memory for surfaces.
+     */
+    SUBREASON_KILL_PID = 12;
+
+    /**
+     * The start of the process was invalid.
+     */
+    SUBREASON_INVALID_START = 13;
+
+    /**
+     * The process was killed because it's in an invalid state, typically
+     * it's triggered from SHELL.
+     */
+    SUBREASON_INVALID_STATE = 14;
+
+    /**
+     * The process was killed when it's imperceptible to user, because it was
+     * in a bad state.
+     */
+    SUBREASON_IMPERCEPTIBLE = 15;
+
+    /**
+     * The process was killed because it's being moved out from LRU list.
+     */
+    SUBREASON_REMOVE_LRU = 16;
+
+    /**
+     * The process was killed because it's isolated and was in a cached state.
+     */
+    SUBREASON_ISOLATED_NOT_NEEDED = 17;
+}
+
+/**
+ * The relative importance level that the system places on a process.
+ * Keep sync with the definitions in
+ * {@link android.app.ActivityManager.RunningAppProcessInfo}
+ */
+enum Importance {
+    option allow_alias = true;
+
+    IMPORTANCE_FOREGROUND = 100;
+    IMPORTANCE_FOREGROUND_SERVICE = 125;
+    IMPORTANCE_TOP_SLEEPING_PRE_28 = 150;
+    IMPORTANCE_VISIBLE = 200;
+    IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
+    IMPORTANCE_PERCEPTIBLE = 230;
+    IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
+    IMPORTANCE_SERVICE = 300;
+    IMPORTANCE_TOP_SLEEPING = 325;
+    IMPORTANCE_CANT_SAVE_STATE = 350;
+    IMPORTANCE_CACHED = 400;
+    IMPORTANCE_BACKGROUND = 400;
+    IMPORTANCE_EMPTY = 500;
+    IMPORTANCE_GONE = 1000;
+}
diff --git a/core/proto/android/app/appexitinfo.proto b/core/proto/android/app/appexitinfo.proto
index 6a49220..66173f6 100644
--- a/core/proto/android/app/appexitinfo.proto
+++ b/core/proto/android/app/appexitinfo.proto
@@ -20,6 +20,7 @@
 package android.app;
 
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/app/appexit_enums.proto";
 
 /**
  * An android.app.ApplicationExitInfo object.
@@ -33,150 +34,9 @@
     optional int32 defining_uid = 4;
     optional string process_name = 5;
     optional int32 connection_group = 6;
-
-    enum ReasonCode {
-        /**
-         * Application process died due to unknown reason.
-         */
-        REASON_UNKNOWN = 0;
-
-        /**
-         * Application process exit normally by itself, for example,
-         * via {@link android.os.Process#exit}; {@link #status} will specify the exit code.
-         *
-         * <p>Applications should normally not do this, as the system has a better knowledge
-         * in terms of process management.</p>
-         */
-        REASON_EXIT_SELF = 1;
-
-        /**
-         * Application process died due to the result of an OS signal; for example,
-         * {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum.
-         */
-        REASON_SIGNALED = 2;
-
-        /**
-         * Application process was killed by the system low memory killer, meaning the system was
-         * under memory pressure at the time of kill.
-         */
-        REASON_LOW_MEMORY = 3;
-
-        /**
-         * Application process died because of an unhandled exception in Java code.
-         */
-        REASON_CRASH = 4;
-
-        /**
-         * Application process died because it's crashed due to a native code crash.
-         */
-        REASON_CRASH_NATIVE = 5;
-
-        /**
-         * Application process was killed due to being unresponsive (ANR).
-         */
-        REASON_ANR = 6;
-
-        /**
-         * Application process was killed because it took too long to attach to the system
-         * during the start.
-         */
-        REASON_INITIALIZATION_FAILURE = 7;
-
-        /**
-         * Application process was killed because of initialization failure,
-         * for example, it took too long to attach to the system during the start,
-         * or there was an error during initialization.
-         */
-        REASON_PERMISSION_CHANGE = 8;
-
-        /**
-         * Application process was killed by the activity manager due to excessive resource usage.
-         */
-        REASON_EXCESSIVE_RESOURCE_USAGE = 9;
-
-        /**
-         * Application process was killed by the system for various other reasons,
-         * for example, the application package got disabled by the user;
-         * {@link #description} will specify the cause given by the system.
-         */
-        REASON_OTHER = 10;
-
-    }
-    optional ReasonCode reason = 7;
-
-    enum SubReason {
-        /**
-         * Application process kills subReason is unknown.
-         */
-        SUBREASON_UNKNOWN = 0;
-
-        /**
-         * Application process was killed because user quit it on the "wait for debugger" dialog.
-         */
-        SUBREASON_WAIT_FOR_DEBUGGER = 1;
-
-        /**
-         * Application process was killed by the activity manager because there were too many cached
-         * processes.
-         */
-        SUBREASON_TOO_MANY_CACHED = 2;
-
-        /**
-         * Application process was killed by the activity manager because there were too many empty
-         * processes.
-         */
-        SUBREASON_TOO_MANY_EMPTY = 3;
-
-        /**
-         * Application process was killed by the activity manager because there were too many cached
-         * processes and this process had been in empty state for a long time.
-         */
-        SUBREASON_TRIM_EMPTY = 4;
-
-        /**
-         * Application process was killed by the activity manager because system was on
-         * memory pressure and this process took large amount of cached memory.
-         */
-        SUBREASON_LARGE_CACHED = 5;
-
-        /**
-         * Application process was killed by the activity manager because the system was on
-         * low memory pressure for a significant amount of time since last idle.
-         */
-        SUBREASON_MEMORY_PRESSURE = 6;
-
-        /**
-         * Application process was killed by the activity manager due to excessive CPU usage.
-         */
-        SUBREASON_EXCESSIVE_CPU = 7;
-    }
-
-    optional SubReason sub_reason = 8;
-
+    optional AppExitReasonCode reason = 7;
+    optional AppExitSubReasonCode sub_reason = 8;
     optional int32 status = 9;
-
-    enum Importance {
-        option allow_alias = true;
-        /**
-         * Keep sync with the definitions in
-         * {@link android.app.ActivityManager.RunningAppProcessInfo}
-         */
-        IMPORTANCE_FOREGROUND = 100;
-        IMPORTANCE_FOREGROUND_SERVICE = 125;
-        IMPORTANCE_TOP_SLEEPING_PRE_28 = 150;
-        IMPORTANCE_VISIBLE = 200;
-        IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
-        IMPORTANCE_PERCEPTIBLE = 230;
-        IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
-        IMPORTANCE_SERVICE = 300;
-        IMPORTANCE_TOP_SLEEPING = 325;
-        IMPORTANCE_CANT_SAVE_STATE = 350;
-        IMPORTANCE_CACHED = 400;
-        IMPORTANCE_BACKGROUND = 400;
-        IMPORTANCE_EMPTY = 500;
-        IMPORTANCE_GONE = 1000;
-    }
-
     optional Importance importance = 10;
     optional int64 pss = 11;
     optional int64 rss = 12;
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6d9e8ab..a3313b2 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -77,6 +77,7 @@
         optional SettingProto interactive_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
         // Settings for magnification mode
         optional SettingProto accessibility_magnification_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto button_long_press_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2356b17..addcd81 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5385,26 +5385,36 @@
         <xliff:g id="package_name" example="com.android.example">%1$s</xliff:g> has been put into the RESTRICTED bucket</string>
 
     <!-- ResolverActivity - profile tabs -->
-    <!-- Label for the perosnal tab of the share sheet and intent resolver [CHAR LIMIT=NONE] -->
+    <!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
     <string name="resolver_personal_tab">Personal</string>
-    <!-- Label for the work tab of the share sheet and intent resolver [CHAR LIMIT=NONE] -->
+    <!-- Label of a tab on a screen. A user can tap this tab to switch to the 'Work' view (that shows their work content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
     <string name="resolver_work_tab">Work</string>
-    <!-- Label to indicate that the user cannot share with work apps [CHAR LIMIT=NONE] -->
+    <!-- Accessibility label for the personal tab button. [CHAR LIMIT=NONE] -->
+    <string name="resolver_personal_tab_accessibility">Personal view</string>
+    <!-- Accessibility label for the work tab button. [CHAR LIMIT=NONE] -->
+    <string name="resolver_work_tab_accessibility">Work view</string>
+    <!-- Title of a screen. This text lets the user know that their IT admin doesn't allow them to share personal content with work apps. [CHAR LIMIT=NONE] -->
     <string name="resolver_cant_share_with_work_apps">Can\u2019t share with work apps</string>
-    <!-- Label to indicate that the user cannot share with personal apps [CHAR LIMIT=NONE] -->
+    <!-- Title of a screen. This text lets the user know that their IT admin doesn't allow them to share work content with personal apps. [CHAR LIMIT=NONE] -->
     <string name="resolver_cant_share_with_personal_apps">Can\u2019t share with personal apps</string>
-    <!-- Label to explain to the user that sharing between personal and work apps is not enabled by the IT admin [CHAR LIMIT=NONE] -->
-    <string name="resolver_cant_share_cross_profile_explanation">Your IT admin blocked sharing between personal and work apps</string>
-    <!-- Label to indicate that the user has to turn on work apps in order to access work data [CHAR LIMIT=NONE] -->
-    <string name="resolver_turn_on_work_apps">Turn on work apps</string>
-    <!-- Label to explain that the user has to turn on work apps in order to access work data [CHAR LIMIT=NONE] -->
-    <string name="resolver_turn_on_work_apps_explanation">Turn on work apps to access work apps &amp; contacts</string>
-    <!-- Label to indicate that no apps are resolved [CHAR LIMIT=NONE] -->
+    <!-- Error message. This text is explaining that the user's IT admin doesn't allow sharing between personal and work apps. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_share_cross_profile_explanation">Your IT admin blocked sharing between personal and work profiles</string>
+    <!-- Title of an error screen. This error message lets the user know that their IT admin blocked access to work apps, and the personal content that they're trying to view in a work app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_work_apps">Can\u2019t access work apps</string>
+    <!-- Error message. This message lets the user know that their IT admin blocked access to work apps, and the personal content that they're trying to view in a work app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_work_apps_explanation">Your IT admin doesn\u2019t let you view personal content in work apps</string>
+    <!-- Title of an error screen. This error message lets the user know that their IT admin blocked access to personal apps, and the work content that they're trying to view in a personal app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_personal_apps">Can\u2019t access personal apps</string>
+    <!-- Error message. This message lets the user know that their IT admin blocked access to personal apps, and the work content that they're trying to view in a personal app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_personal_apps_explanation">Your IT admin doesn\u2019t let you view work content in personal apps</string>
+    <!-- Error message. This text lets the user know that they need to turn on work apps in order to share content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
+    <string name="resolver_turn_on_work_apps_share">Turn on work profile to share content</string>
+    <!-- Error message. This text lets the user know that they need to turn on work apps in order to view content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
+    <string name="resolver_turn_on_work_apps_view">Turn on work profile to view content</string>
+    <!-- Error message. This text lets the user know that work apps aren't available on the device. [CHAR LIMIT=NONE] -->
     <string name="resolver_no_apps_available">No apps available</string>
-    <!-- Label to explain that no apps are resolved [CHAR LIMIT=NONE] -->
-    <string name="resolver_no_apps_available_explanation">We couldn\u2019t find any apps</string>
-    <!-- Button which switches on the disabled work profile [CHAR LIMIT=NONE] -->
-    <string name="resolver_switch_on_work">Switch on work</string>
+    <!-- Button text. This button turns on a user's work profile so they can access their work apps and data. [CHAR LIMIT=NONE] -->
+    <string name="resolver_switch_on_work">Turn on</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
     <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c1d8168..0971aad 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3874,7 +3874,9 @@
   <java-symbol type="color" name="resolver_tabs_active_color" />
   <java-symbol type="color" name="resolver_tabs_inactive_color" />
   <java-symbol type="string" name="resolver_personal_tab" />
+  <java-symbol type="string" name="resolver_personal_tab_accessibility" />
   <java-symbol type="string" name="resolver_work_tab" />
+  <java-symbol type="string" name="resolver_work_tab_accessibility" />
   <java-symbol type="id" name="stub" />
   <java-symbol type="id" name="resolver_empty_state" />
   <java-symbol type="id" name="resolver_empty_state_icon" />
@@ -3886,11 +3888,13 @@
   <java-symbol type="string" name="resolver_cant_share_with_work_apps" />
   <java-symbol type="string" name="resolver_cant_share_with_personal_apps" />
   <java-symbol type="string" name="resolver_cant_share_cross_profile_explanation" />
-  <java-symbol type="string" name="resolver_turn_on_work_apps" />
-  <java-symbol type="string" name="resolver_turn_on_work_apps_explanation" />
+  <java-symbol type="string" name="resolver_cant_access_work_apps" />
+  <java-symbol type="string" name="resolver_cant_access_work_apps_explanation" />
+  <java-symbol type="string" name="resolver_cant_access_personal_apps" />
+  <java-symbol type="string" name="resolver_cant_access_personal_apps_explanation" />
+  <java-symbol type="string" name="resolver_turn_on_work_apps_view" />
+  <java-symbol type="string" name="resolver_turn_on_work_apps_share" />
   <java-symbol type="string" name="resolver_no_apps_available" />
-  <java-symbol type="string" name="resolver_no_apps_available_explanation" />
-  <java-symbol type="string" name="resolver_no_apps_available_explanation" />
   <java-symbol type="string" name="resolver_switch_on_work" />
   <java-symbol type="drawable" name="ic_work_apps_off" />
   <java-symbol type="drawable" name="ic_sharing_disabled" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index eb760b9..8d51a60 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -53,10 +53,7 @@
         "android.test.base",
         "android.test.mock",
         "framework-atb-backward-compatibility",
-        // TODO(b/149928788): Remove this when statsd tests move into the statsd dir.
-        "framework-statsd",
         "framework",
-        "icing-java-proto-lite",
         "ext",
         "framework-res",
     ],
diff --git a/core/tests/coretests/src/android/app/PullAtomMetadataTest.java b/core/tests/coretests/src/android/app/PullAtomMetadataTest.java
deleted file mode 100644
index 0ae6134..0000000
--- a/core/tests/coretests/src/android/app/PullAtomMetadataTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.StatsManager.PullAtomMetadata;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class PullAtomMetadataTest {
-
-    @Test
-    public void testEmpty() {
-        PullAtomMetadata metadata = new PullAtomMetadata.Builder().build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
-        assertThat(metadata.getAdditiveFields()).isNull();
-    }
-
-    @Test
-    public void testSetTimeoutNs() {
-        long timeoutNs = 500_000_000L;
-        PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setTimeoutNs(timeoutNs).build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(timeoutNs);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
-        assertThat(metadata.getAdditiveFields()).isNull();
-    }
-
-    @Test
-    public void testSetCoolDownNs() {
-        long coolDownNs = 10_000_000_000L;
-        PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setCoolDownNs(coolDownNs).build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(coolDownNs);
-        assertThat(metadata.getAdditiveFields()).isNull();
-    }
-
-    @Test
-    public void testSetAdditiveFields() {
-        int[] fields = {2, 4, 6};
-        PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setAdditiveFields(fields).build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
-        assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
-    }
-
-    @Test
-    public void testSetAllElements() {
-        long timeoutNs = 300L;
-        long coolDownNs = 9572L;
-        int[] fields = {3, 2};
-        PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setTimeoutNs(timeoutNs)
-                .setCoolDownNs(coolDownNs)
-                .setAdditiveFields(fields)
-                .build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(timeoutNs);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(coolDownNs);
-        assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
-    }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
deleted file mode 100644
index 4a4f1367..0000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-@SmallTest
-public class AppSearchDocumentTest {
-    private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
-    private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
-    private static final AppSearchDocument sDocumentProperties1 = new AppSearchDocument
-            .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
-            .build();
-    private static final AppSearchDocument sDocumentProperties2 = new AppSearchDocument
-            .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
-            .build();
-
-    @Test
-    public void testDocumentEquals_Identical() {
-        AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setTtlMillis(1L)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .setProperty("byteKey1", sByteArray1, sByteArray2)
-                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
-                .build();
-        AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setTtlMillis(1L)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .setProperty("byteKey1", sByteArray1, sByteArray2)
-                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
-                .build();
-        assertThat(document1).isEqualTo(document2);
-        assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
-    }
-
-    @Test
-    public void testDocumentEquals_DifferentOrder() {
-        AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .setProperty("byteKey1", sByteArray1, sByteArray2)
-                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .build();
-
-        // Create second document with same parameter but different order.
-        AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
-                .setProperty("byteKey1", sByteArray1, sByteArray2)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .build();
-        assertThat(document1).isEqualTo(document2);
-        assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
-    }
-
-    @Test
-    public void testDocumentEquals_Failure() {
-        AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .build();
-
-        // Create second document with same order but different value.
-        AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("longKey1", 1L, 2L, 4L) // Different
-                .build();
-        assertThat(document1).isNotEqualTo(document2);
-        assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
-    }
-
-    @Test
-    public void testDocumentEquals_Failure_RepeatedFieldOrder() {
-        AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("booleanKey1", true, false, true)
-                .build();
-
-        // Create second document with same order but different value.
-        AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("booleanKey1", true, true, false) // Different
-                .build();
-        assertThat(document1).isNotEqualTo(document2);
-        assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
-    }
-
-    @Test
-    public void testDocumentGetSingleValue() {
-        AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setScore(1)
-                .setTtlMillis(1L)
-                .setProperty("longKey1", 1L)
-                .setProperty("doubleKey1", 1.0)
-                .setProperty("booleanKey1", true)
-                .setProperty("stringKey1", "test-value1")
-                .setProperty("byteKey1", sByteArray1)
-                .setProperty("documentKey1", sDocumentProperties1)
-                .build();
-        assertThat(document.getUri()).isEqualTo("uri1");
-        assertThat(document.getTtlMillis()).isEqualTo(1L);
-        assertThat(document.getSchemaType()).isEqualTo("schemaType1");
-        assertThat(document.getCreationTimestampMillis()).isEqualTo(5);
-        assertThat(document.getScore()).isEqualTo(1);
-        assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
-        assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(1.0);
-        assertThat(document.getPropertyBoolean("booleanKey1")).isTrue();
-        assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
-        assertThat(document.getPropertyBytes("byteKey1"))
-                .asList().containsExactly((byte) 1, (byte) 2, (byte) 3);
-        assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1);
-    }
-
-    @Test
-    public void testDocumentGetArrayValues() {
-        AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .setProperty("byteKey1", sByteArray1, sByteArray2)
-                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
-                .build();
-
-        assertThat(document.getUri()).isEqualTo("uri1");
-        assertThat(document.getSchemaType()).isEqualTo("schemaType1");
-        assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L, 2L, 3L);
-        assertThat(document.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
-                .containsExactly(1.0, 2.0, 3.0);
-        assertThat(document.getPropertyBooleanArray("booleanKey1")).asList()
-                .containsExactly(true, false, true);
-        assertThat(document.getPropertyStringArray("stringKey1")).asList()
-                .containsExactly("test-value1", "test-value2", "test-value3");
-        assertThat(document.getPropertyBytesArray("byteKey1")).asList()
-                .containsExactly(sByteArray1, sByteArray2);
-        assertThat(document.getPropertyDocumentArray("documentKey1")).asList()
-                .containsExactly(sDocumentProperties1, sDocumentProperties2);
-    }
-
-    @Test
-    public void testDocumentGetValues_DifferentTypes() {
-        AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setScore(1)
-                .setProperty("longKey1", 1L)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .build();
-
-        // Get a value for a key that doesn't exist
-        assertThat(document.getPropertyDouble("doubleKey1")).isNull();
-        assertThat(document.getPropertyDoubleArray("doubleKey1")).isNull();
-
-        // Get a value with a single element as an array and as a single value
-        assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
-        assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L);
-
-        // Get a value with multiple elements as an array and as a single value
-        assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
-        assertThat(document.getPropertyStringArray("stringKey1")).asList()
-                .containsExactly("test-value1", "test-value2", "test-value3");
-
-        // Get a value of the wrong type
-        assertThat(document.getPropertyDouble("longKey1")).isNull();
-        assertThat(document.getPropertyDoubleArray("longKey1")).isNull();
-    }
-
-    @Test
-    public void testDocumentInvalid() {
-        AppSearchDocument.Builder builder = new AppSearchDocument.Builder("uri1", "schemaType1");
-        assertThrows(
-                IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{}));
-    }
-
-    @Test
-    public void testDocumentProtoPopulation() {
-        AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setScore(1)
-                .setTtlMillis(1L)
-                .setProperty("longKey1", 1L)
-                .setProperty("doubleKey1", 1.0)
-                .setProperty("booleanKey1", true)
-                .setProperty("stringKey1", "test-value1")
-                .setProperty("byteKey1", sByteArray1)
-                .setProperty("documentKey1", sDocumentProperties1)
-                .build();
-
-        // Create the Document proto. Need to sort the property order by key.
-        DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
-                .setUri("uri1")
-                .setSchema("schemaType1")
-                .setCreationTimestampMs(5L)
-                .setScore(1)
-                .setTtlMs(1L);
-        HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
-        propertyProtoMap.put("longKey1",
-                PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
-        propertyProtoMap.put("doubleKey1",
-                PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0));
-        propertyProtoMap.put("booleanKey1",
-                PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true));
-        propertyProtoMap.put("stringKey1",
-                PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1"));
-        propertyProtoMap.put("byteKey1",
-                PropertyProto.newBuilder().setName("byteKey1").addBytesValues(
-                        ByteString.copyFrom(sByteArray1)));
-        propertyProtoMap.put("documentKey1",
-                PropertyProto.newBuilder().setName("documentKey1")
-                        .addDocumentValues(sDocumentProperties1.getProto()));
-        List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
-        Collections.sort(sortedKey);
-        for (String key : sortedKey) {
-            documentProtoBuilder.addProperties(propertyProtoMap.get(key));
-        }
-        assertThat(document.getProto()).isEqualTo(documentProtoBuilder.build());
-    }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java
deleted file mode 100644
index 6aa16cc..0000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-@SmallTest
-public class AppSearchEmailTest {
-
-    @Test
-    public void testBuildEmailAndGetValue() {
-        AppSearchEmail email = new AppSearchEmail.Builder("uri")
-                .setFrom("FakeFromAddress")
-                .setCc("CC1", "CC2")
-                // Score and Property are mixed into the middle to make sure DocumentBuilder's
-                // methods can be interleaved with EmailBuilder's methods.
-                .setScore(1)
-                .setProperty("propertyKey", "propertyValue1", "propertyValue2")
-                .setSubject("subject")
-                .setBody("EmailBody")
-                .build();
-
-        assertThat(email.getUri()).isEqualTo("uri");
-        assertThat(email.getFrom()).isEqualTo("FakeFromAddress");
-        assertThat(email.getTo()).isNull();
-        assertThat(email.getCc()).asList().containsExactly("CC1", "CC2");
-        assertThat(email.getBcc()).isNull();
-        assertThat(email.getScore()).isEqualTo(1);
-        assertThat(email.getPropertyString("propertyKey")).isEqualTo("propertyValue1");
-        assertThat(email.getPropertyStringArray("propertyKey")).asList().containsExactly(
-                "propertyValue1", "propertyValue2");
-        assertThat(email.getSubject()).isEqualTo("subject");
-        assertThat(email.getBody()).isEqualTo("EmailBody");
-    }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java
deleted file mode 100644
index 08ec2d0..0000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import android.app.appsearch.AppSearchSchema.PropertyConfig;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.IndexingConfig.TokenizerType;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import org.junit.Test;
-
-@SmallTest
-public class AppSearchSchemaTest {
-    @Test
-    public void testGetProto_Email() {
-        AppSearchSchema emailSchema = AppSearchSchema.newBuilder("Email")
-                .addProperty(AppSearchSchema.newPropertyBuilder("subject")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).addProperty(AppSearchSchema.newPropertyBuilder("body")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).build();
-
-        SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
-                .setSchemaType("Email")
-                .addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("subject")
-                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(TokenizerType.Code.PLAIN)
-                                        .setTermMatchType(TermMatchType.Code.PREFIX)
-                        )
-                ).addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("body")
-                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(TokenizerType.Code.PLAIN)
-                                        .setTermMatchType(TermMatchType.Code.PREFIX)
-                        )
-                ).build();
-
-        assertThat(emailSchema.getProto()).isEqualTo(expectedEmailProto);
-    }
-
-    @Test
-    public void testGetProto_MusicRecording() {
-        AppSearchSchema musicRecordingSchema = AppSearchSchema.newBuilder("MusicRecording")
-                .addProperty(AppSearchSchema.newPropertyBuilder("artist")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).addProperty(AppSearchSchema.newPropertyBuilder("pubDate")
-                        .setDataType(PropertyConfig.DATA_TYPE_INT64)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE)
-                        .build()
-                ).build();
-
-        SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
-                .setSchemaType("MusicRecording")
-                .addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("artist")
-                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(TokenizerType.Code.PLAIN)
-                                        .setTermMatchType(TermMatchType.Code.PREFIX)
-                        )
-                ).addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("pubDate")
-                        .setDataType(PropertyConfigProto.DataType.Code.INT64)
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(TokenizerType.Code.NONE)
-                                        .setTermMatchType(TermMatchType.Code.UNKNOWN)
-                        )
-                ).build();
-
-        assertThat(musicRecordingSchema.getProto()).isEqualTo(expectedMusicRecordingProto);
-    }
-
-    @Test
-    public void testInvalidEnums() {
-        PropertyConfig.Builder builder = AppSearchSchema.newPropertyBuilder("test");
-        assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
-        assertThrows(IllegalArgumentException.class, () -> builder.setCardinality(99));
-    }
-
-    @Test
-    public void testMissingFields() {
-        PropertyConfig.Builder builder = AppSearchSchema.newPropertyBuilder("test");
-        Exception e = expectThrows(IllegalSchemaException.class, builder::build);
-        assertThat(e).hasMessageThat().contains("Missing field: dataType");
-
-        builder.setDataType(PropertyConfig.DATA_TYPE_DOCUMENT);
-        e = expectThrows(IllegalSchemaException.class, builder::build);
-        assertThat(e).hasMessageThat().contains("Missing field: schemaType");
-
-        builder.setSchemaType("TestType");
-        e = expectThrows(IllegalSchemaException.class, builder::build);
-        assertThat(e).hasMessageThat().contains("Missing field: cardinality");
-
-        builder.setCardinality(PropertyConfig.CARDINALITY_REPEATED);
-        builder.build();
-    }
-
-    @Test
-    public void testDuplicateProperties() {
-        AppSearchSchema.Builder builder = AppSearchSchema.newBuilder("Email")
-                .addProperty(AppSearchSchema.newPropertyBuilder("subject")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).addProperty(AppSearchSchema.newPropertyBuilder("subject")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                );
-
-        Exception e = expectThrows(IllegalSchemaException.class, builder::build);
-        assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
-    }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java b/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
deleted file mode 100644
index 21259cc..0000000
--- a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static  com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.SearchResultProto;
-
-import org.junit.Test;
-
-@SmallTest
-public class SearchResultsTest {
-
-    @Test
-    public void testSearchResultsEqual() {
-        final String uri = "testUri";
-        final String schemaType = "testSchema";
-        SearchResultProto.ResultProto result1 = SearchResultProto.ResultProto.newBuilder()
-                .setDocument(DocumentProto.newBuilder()
-                        .setUri(uri)
-                        .setSchema(schemaType)
-                        .build())
-                .build();
-        SearchResultProto searchResults1 = SearchResultProto.newBuilder()
-                .addResults(result1)
-                .build();
-        SearchResults res1 = new SearchResults(searchResults1);
-        SearchResultProto.ResultProto result2 = SearchResultProto.ResultProto.newBuilder()
-                .setDocument(DocumentProto.newBuilder()
-                        .setUri(uri)
-                        .setSchema(schemaType)
-                        .build())
-                .build();
-        SearchResultProto searchResults2 = SearchResultProto.newBuilder()
-                .addResults(result2)
-                .build();
-        SearchResults res2 = new SearchResults(searchResults2);
-        assertThat(res1.toString()).isEqualTo(res2.toString());
-    }
-
-    @Test
-    public void buildSearchSpecWithoutTermMatchType() {
-        assertThrows(RuntimeException.class, () -> SearchSpec.newBuilder()
-                .setSchemaTypes("testSchemaType")
-                .build());
-    }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java b/core/tests/coretests/src/android/app/appsearch/SnippetTest.java
deleted file mode 100644
index 3103708..0000000
--- a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SnippetMatchProto;
-import com.google.android.icing.proto.SnippetProto;
-
-import org.junit.Test;
-
-@SmallTest
-public class SnippetTest {
-
-    // TODO(sidchhabra): Add tests for Double and Long Snippets.
-    @Test
-    public void testSingleStringSnippet() {
-
-        final String propertyKeyString = "content";
-        final String propertyValueString = "A commonly used fake word is foo.\n"
-                + "   Another nonsense word that’s used a lot\n"
-                + "   is bar.\n";
-        final String uri = "uri1";
-        final String schemaType = "schema1";
-        final String searchWord = "foo";
-        final String exactMatch = "foo";
-        final String window = "is foo";
-
-        // Building the SearchResult received from query.
-        PropertyProto property = PropertyProto.newBuilder()
-                .setName(propertyKeyString)
-                .addStringValues(propertyValueString)
-                .build();
-        DocumentProto documentProto = DocumentProto.newBuilder()
-                .setUri(uri)
-                .setSchema(schemaType)
-                .addProperties(property)
-                .build();
-        SnippetProto snippetProto = SnippetProto.newBuilder()
-                .addEntries(SnippetProto.EntryProto.newBuilder()
-                        .setPropertyName(propertyKeyString)
-                        .addSnippetMatches(SnippetMatchProto.newBuilder()
-                                .setValuesIndex(0)
-                                .setExactMatchPosition(29)
-                                .setExactMatchBytes(3)
-                                .setWindowPosition(26)
-                                .setWindowBytes(6)
-                                .build())
-                        .build())
-                .build();
-        SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
-                .setDocument(documentProto)
-                .setSnippet(snippetProto)
-                .build();
-        SearchResultProto searchResultProto = SearchResultProto.newBuilder()
-                .addResults(resultProto)
-                .build();
-        SearchResults searchResults = new SearchResults(searchResultProto);
-
-        // Making ResultReader and getting Snippet values.
-        while (searchResults.hasNext()) {
-            SearchResults.Result result = searchResults.next();
-            MatchInfo match = result.getMatchInfo().get(0);
-            assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
-            assertThat(match.getFullText()).isEqualTo(propertyValueString);
-            assertThat(match.getExactMatch()).isEqualTo(exactMatch);
-            assertThat(match.getSnippet()).isEqualTo(window);
-        }
-    }
-
-    // TODO(sidchhabra): Add tests for Double and Long Snippets.
-    @Test
-    public void testNoSnippets() {
-
-        final String propertyKeyString = "content";
-        final String propertyValueString = "A commonly used fake word is foo.\n"
-                + "   Another nonsense word that’s used a lot\n"
-                + "   is bar.\n";
-        final String uri = "uri1";
-        final String schemaType = "schema1";
-        final String searchWord = "foo";
-        final String exactMatch = "foo";
-        final String window = "is foo";
-
-        // Building the SearchResult received from query.
-        PropertyProto property = PropertyProto.newBuilder()
-                .setName(propertyKeyString)
-                .addStringValues(propertyValueString)
-                .build();
-        DocumentProto documentProto = DocumentProto.newBuilder()
-                .setUri(uri)
-                .setSchema(schemaType)
-                .addProperties(property)
-                .build();
-        SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
-                .setDocument(documentProto)
-                .build();
-        SearchResultProto searchResultProto = SearchResultProto.newBuilder()
-                .addResults(resultProto)
-                .build();
-        SearchResults searchResults = new SearchResults(searchResultProto);
-
-        while (searchResults.hasNext()) {
-            SearchResults.Result result = searchResults.next();
-            assertThat(result.getMatchInfo()).isEqualTo(null);
-        }
-    }
-
-    @Test
-    public void testMultipleStringSnippet() {
-        final String searchWord = "Test";
-
-        // Building the SearchResult received from query.
-        PropertyProto property1 = PropertyProto.newBuilder()
-                .setName("sender.name")
-                .addStringValues("Test Name Jr.")
-                .build();
-        PropertyProto property2 = PropertyProto.newBuilder()
-                .setName("sender.email")
-                .addStringValues("TestNameJr@gmail.com")
-                .build();
-        DocumentProto documentProto = DocumentProto.newBuilder()
-                .setUri("uri1")
-                .setSchema("schema1")
-                .addProperties(property1)
-                .addProperties(property2)
-                .build();
-        SnippetProto snippetProto = SnippetProto.newBuilder()
-                .addEntries(
-                        SnippetProto.EntryProto.newBuilder()
-                                .setPropertyName("sender.name")
-                                .addSnippetMatches(
-                                        SnippetMatchProto.newBuilder()
-                                                .setValuesIndex(0)
-                                                .setExactMatchPosition(0)
-                                                .setExactMatchBytes(4)
-                                                .setWindowPosition(0)
-                                                .setWindowBytes(9)
-                                                .build())
-                                .build())
-                .addEntries(
-                        SnippetProto.EntryProto.newBuilder()
-                                .setPropertyName("sender.email")
-                                .addSnippetMatches(
-                                        SnippetMatchProto.newBuilder()
-                                                .setValuesIndex(0)
-                                                .setExactMatchPosition(0)
-                                                .setExactMatchBytes(20)
-                                                .setWindowPosition(0)
-                                                .setWindowBytes(20)
-                                                .build())
-                                .build()
-                )
-                .build();
-        SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
-                .setDocument(documentProto)
-                .setSnippet(snippetProto)
-                .build();
-        SearchResultProto searchResultProto = SearchResultProto.newBuilder()
-                .addResults(resultProto)
-                .build();
-        SearchResults searchResults = new SearchResults(searchResultProto);
-
-        // Making ResultReader and getting Snippet values.
-        while (searchResults.hasNext()) {
-            SearchResults.Result result = searchResults.next();
-
-            MatchInfo match1 = result.getMatchInfo().get(0);
-            assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
-            assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
-            assertThat(match1.getExactMatch()).isEqualTo("Test");
-            assertThat(match1.getSnippet()).isEqualTo("Test Name");
-
-            MatchInfo match2 = result.getMatchInfo().get(1);
-            assertThat(match2.getPropertyPath()).isEqualTo("sender.email");
-            assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
-            assertThat(match2.getExactMatch()).isEqualTo("TestNameJr@gmail.com");
-            assertThat(match2.getSnippet()).isEqualTo("TestNameJr@gmail.com");
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java
deleted file mode 100644
index b29483c..0000000
--- a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.annotation.NonNull;
-import android.app.appsearch.AppSearchDocument;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Tests that {@link AppSearchDocument} and {@link AppSearchDocument.Builder} are extendable by
- * developers.
- *
- * <p>This class is intentionally in a different package than {@link AppSearchDocument} to make sure
- * there are no package-private methods required for external developers to add custom types.
- */
-@SmallTest
-public class CustomerDocumentTest {
-
-    private static byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
-    private static byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
-    private static AppSearchDocument sDocumentProperties1 = new AppSearchDocument
-            .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
-            .build();
-    private static AppSearchDocument sDocumentProperties2 = new AppSearchDocument
-            .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
-            .build();
-
-    @Test
-    public void testBuildCustomerDocument() {
-        CustomerDocument customerDocument = new CustomerDocument.Builder("uri1")
-                .setScore(1)
-                .setCreationTimestampMillis(0)
-                .setProperty("longKey1", 1L, 2L, 3L)
-                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
-                .setProperty("booleanKey1", true, false, true)
-                .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
-                .setProperty("byteKey1", sByteArray1, sByteArray2)
-                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
-                .build();
-
-        assertThat(customerDocument.getUri()).isEqualTo("uri1");
-        assertThat(customerDocument.getSchemaType()).isEqualTo("customerDocument");
-        assertThat(customerDocument.getScore()).isEqualTo(1);
-        assertThat(customerDocument.getCreationTimestampMillis()).isEqualTo(0L);
-        assertThat(customerDocument.getPropertyLongArray("longKey1")).asList()
-                .containsExactly(1L, 2L, 3L);
-        assertThat(customerDocument.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
-                .containsExactly(1.0, 2.0, 3.0);
-        assertThat(customerDocument.getPropertyBooleanArray("booleanKey1")).asList()
-                .containsExactly(true, false, true);
-        assertThat(customerDocument.getPropertyStringArray("stringKey1")).asList()
-                .containsExactly("test-value1", "test-value2", "test-value3");
-        assertThat(customerDocument.getPropertyBytesArray("byteKey1")).asList()
-                .containsExactly(sByteArray1, sByteArray2);
-        assertThat(customerDocument.getPropertyDocumentArray("documentKey1")).asList()
-                .containsExactly(sDocumentProperties1, sDocumentProperties2);
-    }
-
-    /**
-     * An example document type for test purposes, defined outside of
-     * {@link android.app.appsearch.AppSearch} (the way an external developer would define it).
-     */
-    private static class CustomerDocument extends AppSearchDocument {
-        private CustomerDocument(AppSearchDocument document) {
-            super(document);
-        }
-
-        public static class Builder extends AppSearchDocument.Builder<CustomerDocument.Builder> {
-            private Builder(@NonNull String uri) {
-                super(uri, "customerDocument");
-            }
-
-            @Override
-            public CustomerDocument build() {
-                return new CustomerDocument(super.build());
-            }
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java b/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java
index 10a7b76..d8088b7 100644
--- a/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java
+++ b/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java
@@ -56,16 +56,6 @@
     }
 
     @Test
-    public void testUnparcelingCorrectClass_multiFloat() {
-        ControlAction toParcel = new MultiFloatAction(TEST_ID, new float[] {0f, 1f});
-
-        ControlAction fromParcel = parcelAndUnparcel(toParcel);
-
-        assertEquals(ControlAction.TYPE_MULTI_FLOAT, fromParcel.getActionType());
-        assertTrue(fromParcel instanceof MultiFloatAction);
-    }
-
-    @Test
     public void testUnparcelingCorrectClass_mode() {
         ControlAction toParcel = new ModeAction(TEST_ID, 1);
 
diff --git a/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java b/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java
index 292ac09..87dc1b7 100644
--- a/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java
+++ b/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java
@@ -103,16 +103,6 @@
     }
 
     @Test
-    public void testUnparcelingCorrectClass_thumbnail() {
-        ControlTemplate toParcel = new ThumbnailTemplate(TEST_ID, mIcon, TEST_ACTION_DESCRIPTION);
-
-        ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
-
-        assertEquals(ControlTemplate.TYPE_THUMBNAIL, fromParcel.getTemplateType());
-        assertTrue(fromParcel instanceof ThumbnailTemplate);
-    }
-
-    @Test
     public void testUnparcelingCorrectClass_toggleRange() {
         ControlTemplate toParcel = new ToggleRangeTemplate(TEST_ID, mControlButton,
                 new RangeTemplate(TEST_ID, 0, 2, 1, 1, "%f"));
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 6d0e58b..24e96d4 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -1340,7 +1340,7 @@
         onView(withText(R.string.resolver_work_tab)).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_turn_on_work_apps))
+        onView(withText(R.string.resolver_turn_on_work_apps_share))
                 .check(matches(isDisplayed()));
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index a7bf488..9d1ca61 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -624,7 +624,7 @@
         onView(withText(R.string.resolver_work_tab)).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_turn_on_work_apps))
+        onView(withText(R.string.resolver_turn_on_work_apps_view))
                 .check(matches(isDisplayed()));
     }
 
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 5d2e303..38e18a9 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -39,6 +39,7 @@
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.OBSERVE_NETWORK_POLICY"/>
         <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
+        <permission name="android.permission.PACKAGE_USAGE_STATS" />
         <permission name="android.permission.READ_DREAM_STATE"/>
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index d683041..d9d2eea 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -1264,8 +1264,7 @@
          * successfully.
          *
          * @param timeout duration in seconds or {@code 0} if user authentication must take place
-         *        for every use of the key. {@code -1} is also accepted for legacy purposes. It is
-         *        functionally the same as {@code 0}.
+         *        for every use of the key.
          * @param type set of authentication types which can authorize use of the key. See
          *        {@link KeyProperties}.{@code AUTH} flags.
          *
@@ -1275,12 +1274,10 @@
          * @see KeyguardManager
          */
         @NonNull
-        public Builder setUserAuthenticationParameters(@IntRange(from = -1) int timeout,
+        public Builder setUserAuthenticationParameters(@IntRange(from = 0) int timeout,
                                                        @KeyProperties.AuthEnum int type) {
-            if (timeout < -1) {
-                throw new IllegalArgumentException("timeout must be -1 or larger");
-            } else if (timeout == -1) {
-                timeout = 0;
+            if (timeout < 0) {
+                throw new IllegalArgumentException("timeout must be 0 or larger");
             }
             mUserAuthenticationValidityDurationSeconds = timeout;
             mUserAuthenticationType = type;
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index e230b7c..8120a93 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -894,8 +894,7 @@
          * successfully.
          *
          * @param timeout duration in seconds or {@code 0} if user authentication must take place
-         *        for every use of the key. {@code -1} is also accepted for legacy purposes. It is
-         *        functionally the same as {@code 0}.
+         *        for every use of the key.
          * @param type set of authentication types which can authorize use of the key. See
          *        {@link KeyProperties}.{@code AUTH} flags.
          *
@@ -905,12 +904,10 @@
          * @see KeyguardManager
          */
         @NonNull
-        public Builder setUserAuthenticationParameters(@IntRange(from = -1) int timeout,
+        public Builder setUserAuthenticationParameters(@IntRange(from = 0) int timeout,
                                                        @KeyProperties.AuthEnum int type) {
-            if (timeout < -1) {
-                throw new IllegalArgumentException("timeout must be -1 or larger");
-            } else if (timeout == -1) {
-                timeout = 0;
+            if (timeout < 0) {
+                throw new IllegalArgumentException("timeout must be 0 or larger");
             }
             mUserAuthenticationValidityDurationSeconds = timeout;
             mUserAuthenticationType = type;
diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp
new file mode 100644
index 0000000..308c1a5
--- /dev/null
+++ b/libs/WindowManager/Jetpack/Android.bp
@@ -0,0 +1,38 @@
+// 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_library_import {
+    name: "window-extensions",
+    aars: ["window-extensions-release.aar"],
+    sdk_version: "current",
+}
+
+java_library {
+    name: "androidx.window.extensions",
+    srcs: ["src/**/*.java"],
+    static_libs: ["window-extensions"],
+    installable: true,
+    sdk_version: "core_platform",
+    vendor: true,
+    libs: ["framework", "androidx.annotation_annotation",],
+    required: ["androidx.window.extensions.xml",],
+}
+
+prebuilt_etc {
+    name: "androidx.window.extensions.xml",
+    vendor: true,
+    sub_dir: "permissions",
+    src: "androidx.window.extensions.xml",
+    filename_from_src: true,
+}
diff --git a/libs/WindowManager/Jetpack/androidx.window.extensions.xml b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
new file mode 100644
index 0000000..1f0ff66
--- /dev/null
+++ b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<permissions>
+    <library
+        name="androidx.window.extensions"
+        file="/vendor/framework/androidx.window.extensions.jar"/>
+</permissions>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
new file mode 100644
index 0000000..c4f11a0
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions;
+
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+/**
+ * Toolkit class for calculation of the display feature bounds within the window.
+ * NOTE: This sample implementation only works for Activity windows, because there is no public APIs
+ * to obtain layout params or bounds for arbitrary windows.
+ */
+class ExtensionHelper {
+    /**
+     * Rotate the input rectangle specified in default display orientation to the current display
+     * rotation.
+     */
+    static void rotateRectToDisplayRotation(Rect inOutRect, int displayId) {
+        DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+        DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+        int rotation = displayInfo.rotation;
+
+        boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
+        int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+        int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+
+        inOutRect.intersect(0, 0, displayWidth, displayHeight);
+
+        rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
+    }
+
+    /**
+     * Rotate the input rectangle within parent bounds for a given delta.
+     */
+    private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
+            @Surface.Rotation int delta) {
+        int origLeft = inOutRect.left;
+        switch (delta) {
+            case ROTATION_0:
+                return;
+            case ROTATION_90:
+                inOutRect.left = inOutRect.top;
+                inOutRect.top = parentWidth - inOutRect.right;
+                inOutRect.right = inOutRect.bottom;
+                inOutRect.bottom = parentWidth - origLeft;
+                return;
+            case ROTATION_180:
+                inOutRect.left = parentWidth - inOutRect.right;
+                inOutRect.right = parentWidth - origLeft;
+                return;
+            case ROTATION_270:
+                inOutRect.left = parentHeight - inOutRect.bottom;
+                inOutRect.bottom = inOutRect.right;
+                inOutRect.right = parentHeight - inOutRect.top;
+                inOutRect.top = origLeft;
+                return;
+        }
+    }
+
+    /** Transform rectangle from absolute coordinate space to the window coordinate space. */
+    static void transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken) {
+        Rect windowRect = getWindowRect(windowToken);
+        if (windowRect == null) {
+            inOutRect.setEmpty();
+            return;
+        }
+        if (!Rect.intersects(inOutRect, windowRect)) {
+            inOutRect.setEmpty();
+            return;
+        }
+        inOutRect.intersect(windowRect);
+        inOutRect.offset(-windowRect.left, -windowRect.top);
+    }
+
+    /**
+     * Get the current window bounds in absolute coordinates.
+     * NOTE: Only works with Activity windows.
+     */
+    private static Rect getWindowRect(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        final Rect windowRect = new Rect();
+        if (activity != null) {
+            activity.getWindow().getDecorView().getWindowDisplayFrame(windowRect);
+        }
+        return windowRect;
+    }
+
+    /**
+     * Check if this window is an Activity window that is in multi-window mode.
+     */
+    static boolean isInMultiWindow(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        return activity != null && activity.isInMultiWindowMode();
+    }
+
+    /**
+     * Get the id of the parent display for the window.
+     * NOTE: Only works with Activity windows.
+     */
+    static int getWindowDisplay(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        return activity != null
+                ? activity.getWindowManager().getDefaultDisplay().getDisplayId() : INVALID_DISPLAY;
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
new file mode 100644
index 0000000..47349f1
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions;
+
+import android.content.Context;
+
+/**
+ * Provider class that will instantiate the library implementation. It must be included in the
+ * vendor library, and the vendor implementation must match the signature of this class.
+ */
+public class ExtensionProvider {
+
+    /**
+     * The support library will instantiate the vendor implementation using this interface.
+     * @return An implementation of {@link ExtensionInterface}.
+     */
+    public static ExtensionInterface getExtensionImpl(Context context) {
+        return new SettingsExtensionImpl(context);
+    }
+
+    /**
+     * The support library will use this method to check API version compatibility.
+     * @return API version string in MAJOR.MINOR.PATCH-description format.
+     */
+    public static String getApiVersion() {
+        return "1.0.0-settings_sample";
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
new file mode 100644
index 0000000..7a3fbf3
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static androidx.window.extensions.ExtensionHelper.getWindowDisplay;
+import static androidx.window.extensions.ExtensionHelper.isInMultiWindow;
+import static androidx.window.extensions.ExtensionHelper.rotateRectToDisplayRotation;
+import static androidx.window.extensions.ExtensionHelper.transformToWindowSpaceRect;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SettingsExtensionImpl extends StubExtension {
+    private static final String TAG = "SettingsExtension";
+
+    private static final String DEVICE_POSTURE = "device_posture";
+    private static final String DISPLAY_FEATURES = "display_features";
+
+    private static final Pattern FEATURE_PATTERN =
+            Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");
+
+    private static final String FEATURE_TYPE_FOLD = "fold";
+    private static final String FEATURE_TYPE_HINGE = "hinge";
+
+    private Context mContext;
+    private SettingsObserver mSettingsObserver;
+
+    final class SettingsObserver extends ContentObserver {
+        private final Uri mDevicePostureUri =
+                Settings.Global.getUriFor(DEVICE_POSTURE);
+        private final Uri mDisplayFeaturesUri =
+                Settings.Global.getUriFor(DISPLAY_FEATURES);
+        private final ContentResolver mResolver = mContext.getContentResolver();
+        private boolean mRegisteredObservers;
+
+
+        private SettingsObserver() {
+            super(new Handler(Looper.getMainLooper()));
+        }
+
+        private void registerObserversIfNeeded() {
+            if (mRegisteredObservers) {
+                return;
+            }
+            mRegisteredObservers = true;
+            mResolver.registerContentObserver(mDevicePostureUri, false /* notifyForDescendents */,
+                    this /* ContentObserver */);
+            mResolver.registerContentObserver(mDisplayFeaturesUri, false /* notifyForDescendents */,
+                    this /* ContentObserver */);
+        }
+
+        private void unregisterObserversIfNeeded() {
+            if (!mRegisteredObservers) {
+                return;
+            }
+            mRegisteredObservers = false;
+            mResolver.unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (uri == null) {
+                return;
+            }
+
+            if (mDevicePostureUri.equals(uri)) {
+                updateDevicePosture();
+                return;
+            }
+            if (mDisplayFeaturesUri.equals(uri)) {
+                updateDisplayFeatures();
+                return;
+            }
+        }
+    }
+
+    SettingsExtensionImpl(Context context) {
+        mContext = context;
+        mSettingsObserver = new SettingsObserver();
+    }
+
+    private void updateDevicePosture() {
+        updateDeviceState(getDeviceState());
+    }
+
+    /** Update display features with values read from settings. */
+    private void updateDisplayFeatures() {
+        for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
+            ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
+            updateWindowLayout(windowToken, newLayout);
+        }
+    }
+
+    @NonNull
+    @Override
+    public ExtensionDeviceState getDeviceState() {
+        ContentResolver resolver = mContext.getContentResolver();
+        int posture = Settings.Global.getInt(resolver, DEVICE_POSTURE,
+                ExtensionDeviceState.POSTURE_UNKNOWN);
+        return new ExtensionDeviceState(posture);
+    }
+
+    @NonNull
+    @Override
+    public ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+        List<ExtensionDisplayFeature> displayFeatures = readDisplayFeatures(windowToken);
+        return new ExtensionWindowLayoutInfo(displayFeatures);
+    }
+
+    private List<ExtensionDisplayFeature> readDisplayFeatures(IBinder windowToken) {
+        List<ExtensionDisplayFeature> features = new ArrayList<ExtensionDisplayFeature>();
+        int displayId = getWindowDisplay(windowToken);
+        if (displayId != DEFAULT_DISPLAY) {
+            Log.w(TAG, "This sample doesn't support display features on secondary displays");
+            return features;
+        }
+
+        ContentResolver resolver = mContext.getContentResolver();
+        final String displayFeaturesString = Settings.Global.getString(resolver, DISPLAY_FEATURES);
+        if (isInMultiWindow(windowToken)) {
+            // It is recommended not to report any display features in multi-window mode, since it
+            // won't be possible to synchronize the display feature positions with window movement.
+            return features;
+        }
+        if (TextUtils.isEmpty(displayFeaturesString)) {
+            return features;
+        }
+
+        String[] featureStrings = displayFeaturesString.split(";");
+        for (String featureString : featureStrings) {
+            Matcher featureMatcher = FEATURE_PATTERN.matcher(featureString);
+            if (!featureMatcher.matches()) {
+                Log.e(TAG, "Malformed feature description format: " + featureString);
+                continue;
+            }
+            try {
+                String featureType = featureMatcher.group(1);
+                int type;
+                switch (featureType) {
+                    case FEATURE_TYPE_FOLD:
+                        type = ExtensionDisplayFeature.TYPE_FOLD;
+                        break;
+                    case FEATURE_TYPE_HINGE:
+                        type = ExtensionDisplayFeature.TYPE_HINGE;
+                        break;
+                    default: {
+                        Log.e(TAG, "Malformed feature type: " + featureType);
+                        continue;
+                    }
+                }
+
+                int left = Integer.parseInt(featureMatcher.group(2));
+                int top = Integer.parseInt(featureMatcher.group(3));
+                int right = Integer.parseInt(featureMatcher.group(4));
+                int bottom = Integer.parseInt(featureMatcher.group(5));
+                Rect featureRect = new Rect(left, top, right, bottom);
+                rotateRectToDisplayRotation(featureRect, displayId);
+                transformToWindowSpaceRect(featureRect, windowToken);
+                if (!featureRect.isEmpty()) {
+                    ExtensionDisplayFeature feature =
+                            new ExtensionDisplayFeature(featureRect, type);
+                    features.add(feature);
+                } else {
+                    Log.w(TAG, "Failed to adjust feature to window");
+                }
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "Malformed feature description: " + featureString);
+            }
+        }
+        return features;
+    }
+
+    @Override
+    protected void onListenersChanged() {
+        if (mSettingsObserver == null) {
+            return;
+        }
+
+        if (hasListeners()) {
+            mSettingsObserver.registerObserversIfNeeded();
+        } else {
+            mSettingsObserver.unregisterObserversIfNeeded();
+        }
+    }
+}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
new file mode 100644
index 0000000..0ebbb86
--- /dev/null
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 31e4555..6761435 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,6 +27,7 @@
 #include "DamageAccumulator.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #endif
+#include "utils/FatVector.h"
 #include "utils/MathUtils.h"
 #include "utils/StringUtils.h"
 #include "utils/TraceUtils.h"
@@ -36,7 +37,6 @@
 #include <atomic>
 #include <sstream>
 #include <string>
-#include <ui/FatVector.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c0ec217..d55e5b0 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -27,8 +27,6 @@
 
 #include <androidfw/ResourceTypes.h>
 
-#include <ui/FatVector.h>
-
 #include "AnimatorManager.h"
 #include "CanvasTransform.h"
 #include "Debug.h"
@@ -37,6 +35,7 @@
 #include "RenderProperties.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "pipeline/skia/SkiaLayer.h"
+#include "utils/FatVector.h"
 
 #include <vector>
 
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index a2fef1e..0ce04a2 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -29,9 +29,9 @@
 
 #include <hwui/MinikinSkia.h>
 #include <hwui/Typeface.h>
+#include <utils/FatVector.h>
 #include <minikin/FontFamily.h>
 #include <minikin/LocaleList.h>
-#include <ui/FatVector.h>
 
 #include <memory>
 
@@ -104,7 +104,7 @@
 
 static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
         jint weight, jint italic) {
-    FatVector<SkFontArguments::Axis, 2> skiaAxes;
+    uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
     for (const auto& axis : builder->axes) {
         skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
     }
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 5714cd1..7e8f8d8 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -28,8 +28,8 @@
 
 #include <hwui/MinikinSkia.h>
 #include <hwui/Typeface.h>
+#include <utils/FatVector.h>
 #include <minikin/FontFamily.h>
-#include <ui/FatVector.h>
 
 #include <memory>
 
@@ -93,7 +93,7 @@
     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
             release_global_ref, reinterpret_cast<void*>(fontRef)));
 
-    FatVector<SkFontArguments::Axis, 2> skiaAxes;
+    uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
     for (const auto& axis : builder->axes) {
         skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
     }
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index d669f84..cfc0f9b 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -21,7 +21,7 @@
 
 #include <SkCanvas.h>
 #include <SkDrawable.h>
-#include <ui/FatVector.h>
+#include <utils/FatVector.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 206b58f..cae3e3b 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -27,6 +27,7 @@
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/SkiaVulkanPipeline.h"
 #include "renderstate/RenderState.h"
+#include "utils/FatVector.h"
 #include "utils/TimeUtils.h"
 #include "utils/TraceUtils.h"
 
@@ -39,8 +40,6 @@
 #include <utils/Mutex.h>
 #include <thread>
 
-#include <ui/FatVector.h>
-
 namespace android {
 namespace uirenderer {
 namespace renderthread {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ba70afc..a5355fc 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,13 +23,13 @@
 #include <GrContext.h>
 #include <GrTypes.h>
 #include <android/sync.h>
-#include <ui/FatVector.h>
 #include <vk/GrVkExtensions.h>
 #include <vk/GrVkTypes.h>
 
 #include "Properties.h"
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
+#include "utils/FatVector.h"
 #include "utils/TraceUtils.h"
 
 namespace android {
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 6585a62..8523e6c 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <gtest/gtest.h>
-#include <ui/FatVector.h>
+#include <utils/FatVector.h>
 
 #include <tests/common/TestUtils.h>
 
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
new file mode 100644
index 0000000..49f1984
--- /dev/null
+++ b/libs/hwui/utils/FatVector.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FAT_VECTOR_H
+#define ANDROID_FAT_VECTOR_H
+
+#include "utils/Macros.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+template <typename T, size_t SIZE>
+class InlineStdAllocator {
+public:
+    struct Allocation {
+        PREVENT_COPY_AND_ASSIGN(Allocation);
+
+    public:
+        Allocation(){};
+        // char array instead of T array, so memory is uninitialized, with no destructors run
+        char array[sizeof(T) * SIZE];
+        bool inUse = false;
+    };
+
+    typedef T value_type;  // needed to implement std::allocator
+    typedef T* pointer;    // needed to implement std::allocator
+
+    explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+    InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
+    ~InlineStdAllocator() {}
+
+    T* allocate(size_t num, const void* = 0) {
+        if (!mAllocation.inUse && num <= SIZE) {
+            mAllocation.inUse = true;
+            return (T*)mAllocation.array;
+        } else {
+            return (T*)malloc(num * sizeof(T));
+        }
+    }
+
+    void deallocate(pointer p, size_t num) {
+        if (p == (T*)mAllocation.array) {
+            mAllocation.inUse = false;
+        } else {
+            // 'free' instead of delete here - destruction handled separately
+            free(p);
+        }
+    }
+    Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+    FatVector()
+            : std::vector<T, InlineStdAllocator<T, SIZE>>(
+                      InlineStdAllocator<T, SIZE>(mAllocation)) {
+        this->reserve(SIZE);
+    }
+
+    explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
+
+private:
+    typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+}  // namespace uirenderer
+}  // namespace android
+
+#endif  // ANDROID_FAT_VECTOR_H
diff --git a/libs/incident/include_priv/android/os/IncidentReportArgs.h b/libs/incident/include_priv/android/os/IncidentReportArgs.h
index 0e61590..ec3aabb 100644
--- a/libs/incident/include_priv/android/os/IncidentReportArgs.h
+++ b/libs/incident/include_priv/android/os/IncidentReportArgs.h
@@ -53,6 +53,7 @@
     void setReceiverPkg(const string& pkg);
     void setReceiverCls(const string& cls);
     void addHeader(const vector<uint8_t>& headerProto);
+    void setGzip(bool gzip);
 
     inline bool all() const { return mAll; }
     bool containsSection(int section, bool specific) const;
@@ -61,6 +62,7 @@
     inline const string& receiverPkg() const { return mReceiverPkg; }
     inline const string& receiverCls() const { return mReceiverCls; }
     inline const vector<vector<uint8_t>>& headers() const { return mHeaders; }
+    inline bool gzip() const {return mGzip; }
 
     void merge(const IncidentReportArgs& that);
 
@@ -71,6 +73,7 @@
     int mPrivacyPolicy;
     string mReceiverPkg;
     string mReceiverCls;
+    bool mGzip;
 };
 
 }
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index 9d8a983..db495cf 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -26,7 +26,8 @@
 IncidentReportArgs::IncidentReportArgs()
     :mSections(),
      mAll(false),
-     mPrivacyPolicy(-1)
+     mPrivacyPolicy(-1),
+     mGzip(false)
 {
 }
 
@@ -36,7 +37,8 @@
      mAll(that.mAll),
      mPrivacyPolicy(that.mPrivacyPolicy),
      mReceiverPkg(that.mReceiverPkg),
-     mReceiverCls(that.mReceiverCls)
+     mReceiverCls(that.mReceiverCls),
+     mGzip(that.mGzip)
 {
 }
 
@@ -93,6 +95,11 @@
         return err;
     }
 
+    err = out->writeInt32(mGzip);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
     return NO_ERROR;
 }
 
@@ -149,6 +156,15 @@
     mReceiverPkg = String8(in->readString16()).string();
     mReceiverCls = String8(in->readString16()).string();
 
+    int32_t gzip;
+    err = in->readInt32(&gzip);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (gzip != 0) {
+        mGzip = gzip;
+    }
+
     return OK;
 }
 
@@ -193,6 +209,12 @@
     mHeaders.push_back(headerProto);
 }
 
+void
+IncidentReportArgs::setGzip(bool gzip)
+{
+    mGzip = gzip;
+}
+
 bool
 IncidentReportArgs::containsSection(int section, bool specific) const
 {
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 1ac4b4b..323bba3 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -624,7 +624,7 @@
 
     private void registerGnssStats() {
         mPullAtomCallback = new StatsPullAtomCallbackImpl();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 FrameworkStatsLog.GNSS_STATS,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(), mPullAtomCallback);
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index 7245aab..e67ba59 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -16,10 +16,18 @@
 
 package android.media;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.Log;
 import android.util.Pair;
 
+import java.lang.reflect.ParameterizedType;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Objects;
@@ -30,6 +38,8 @@
  * configuration and capability requests within the Audio Framework.
  */
 public final class AudioMetadata {
+    private static final String TAG = "AudioMetadata";
+
     /**
      * Key interface for the map.
      *
@@ -273,7 +283,7 @@
      * @hide
      */
     @NonNull
-    public static <T> Key<T> createKey(String name, Class<T> type) {
+    public static <T> Key<T> createKey(@NonNull String name, @NonNull Class<T> type) {
         // Implementation specific.
         return new Key<T>() {
             private final String mName = name;
@@ -296,6 +306,26 @@
             public boolean isFromFramework() {
                 return true;
             }
+
+            /**
+             * Return true if the name and the type of two objects are the same.
+             */
+            @Override
+            public boolean equals(Object obj) {
+                if (obj == this) {
+                    return true;
+                }
+                if (!(obj instanceof Key)) {
+                    return false;
+                }
+                Key<?> other = (Key<?>) obj;
+                return mName.equals(other.getName()) && mType.equals(other.getValueClass());
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mName, mType);
+            }
         };
     }
 
@@ -364,6 +394,27 @@
             return mHashMap.size();
         }
 
+        /**
+         * Return true if the object is a BaseMap and the content from two BaseMap are the same.
+         * Note: Need to override the equals functions of Key<T> for HashMap comparison.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (!(obj instanceof BaseMap)) {
+                return false;
+            }
+            BaseMap other = (BaseMap) obj;
+            return mHashMap.equals(other.mHashMap);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mHashMap);
+        }
+
         /*
          * Implementation specific.
          *
@@ -401,6 +452,445 @@
                 new HashMap();
     }
 
+    // The audio metadata object type index should be kept the same as
+    // the ones in audio_utils::metadata::metadata_types
+    private static final int AUDIO_METADATA_OBJ_TYPE_NONE = 0;
+    private static final int AUDIO_METADATA_OBJ_TYPE_INT = 1;
+    private static final int AUDIO_METADATA_OBJ_TYPE_LONG = 2;
+    private static final int AUDIO_METADATA_OBJ_TYPE_FLOAT = 3;
+    private static final int AUDIO_METADATA_OBJ_TYPE_DOUBLE = 4;
+    private static final int AUDIO_METADATA_OBJ_TYPE_STRING = 5;
+    // BaseMap is corresponding to audio_utils::metadata::Data
+    private static final int AUDIO_METADATA_OBJ_TYPE_BASEMAP = 6;
+
+    private static final HashMap<Class, Integer> AUDIO_METADATA_OBJ_TYPES = new HashMap<>() {{
+            put(Integer.class, AUDIO_METADATA_OBJ_TYPE_INT);
+            put(Long.class, AUDIO_METADATA_OBJ_TYPE_LONG);
+            put(Float.class, AUDIO_METADATA_OBJ_TYPE_FLOAT);
+            put(Double.class, AUDIO_METADATA_OBJ_TYPE_DOUBLE);
+            put(String.class, AUDIO_METADATA_OBJ_TYPE_STRING);
+            put(BaseMap.class, AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+        }};
+
+    private static final Charset AUDIO_METADATA_CHARSET = StandardCharsets.UTF_8;
+
+    /**
+     * An auto growing byte buffer
+     */
+    private static class AutoGrowByteBuffer {
+        private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
+        private static final int LONG_BYTE_COUNT = Long.SIZE / Byte.SIZE;
+        private static final int FLOAT_BYTE_COUNT = Float.SIZE / Byte.SIZE;
+        private static final int DOUBLE_BYTE_COUNT = Double.SIZE / Byte.SIZE;
+
+        private ByteBuffer mBuffer;
+
+        AutoGrowByteBuffer() {
+            this(1024);
+        }
+
+        AutoGrowByteBuffer(@IntRange(from = 0) int initialCapacity) {
+            mBuffer = ByteBuffer.allocateDirect(initialCapacity);
+        }
+
+        public ByteBuffer getRawByteBuffer() {
+            // Slice the buffer from 0 to position.
+            int limit = mBuffer.limit();
+            int position = mBuffer.position();
+            mBuffer.limit(position);
+            mBuffer.position(0);
+            ByteBuffer buffer = mBuffer.slice();
+
+            // Restore position and limit.
+            mBuffer.limit(limit);
+            mBuffer.position(position);
+            return buffer;
+        }
+
+        public ByteOrder order() {
+            return mBuffer.order();
+        }
+
+        public int position() {
+            return mBuffer.position();
+        }
+
+        public AutoGrowByteBuffer position(int newPosition) {
+            mBuffer.position(newPosition);
+            return this;
+        }
+
+        public AutoGrowByteBuffer order(ByteOrder order) {
+            mBuffer.order(order);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putInt(int value) {
+            ensureCapacity(INTEGER_BYTE_COUNT);
+            mBuffer.putInt(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putLong(long value) {
+            ensureCapacity(LONG_BYTE_COUNT);
+            mBuffer.putLong(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putFloat(float value) {
+            ensureCapacity(FLOAT_BYTE_COUNT);
+            mBuffer.putFloat(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putDouble(double value) {
+            ensureCapacity(DOUBLE_BYTE_COUNT);
+            mBuffer.putDouble(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer put(byte[] src) {
+            ensureCapacity(src.length);
+            mBuffer.put(src);
+            return this;
+        }
+
+        /**
+         * Ensures capacity to append at least <code>count</code> values.
+         */
+        private void ensureCapacity(@IntRange int count) {
+            if (mBuffer.remaining() < count) {
+                int newCapacity = mBuffer.position() + count;
+                if (newCapacity > Integer.MAX_VALUE >> 1) {
+                    throw new IllegalStateException(
+                            "Item memory requirements too large: " + newCapacity);
+                }
+                newCapacity <<= 1;
+                ByteBuffer buffer = ByteBuffer.allocateDirect(newCapacity);
+                buffer.order(mBuffer.order());
+
+                // Copy data from old buffer to new buffer
+                mBuffer.flip();
+                buffer.put(mBuffer);
+
+                // Set buffer to new buffer
+                mBuffer = buffer;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Describes a unpacking/packing contract of type {@code T} out of a {@link ByteBuffer}
+     *
+     * @param <T> the type being unpack
+     */
+    private interface DataPackage<T> {
+        /**
+         * Read an item from a {@link ByteBuffer}.
+         *
+         * The parceling format is assumed the same as the one described in
+         * audio_utils::Metadata.h. Copied here as a reference.
+         * All values are native endian order.
+         *
+         * Datum = { (type_size_t)  Type (the type index from type_as_value<T>.)
+         *           (datum_size_t) Size (size of datum, including the size field)
+         *           (byte string)  Payload<Type>
+         *         }
+         *
+         * Primitive types:
+         * Payload<Type> = { bytes in native endian order }
+         *
+         * Vector, Map, Container types:
+         * Payload<Type> = { (index_size_t) number of elements
+         *                   (byte string)  Payload<Element_Type> * number
+         *                 }
+         *
+         * Pair container types:
+         * Payload<Type> = { (byte string) Payload<first>,
+         *                   (byte string) Payload<second>
+         *                 }
+         *
+         * @param buffer the byte buffer to read from
+         * @return an object, which types is given type for {@link DataPackage}
+         * @throws BufferUnderflowException when there is no enough data remaining
+         *      in the buffer for unpacking.
+         */
+        @Nullable
+        T unpack(ByteBuffer buffer);
+
+        /**
+         * Pack the item into a byte array. This is the reversed way of unpacking.
+         *
+         * @param output is the stream to which to write the data
+         * @param obj the item to pack
+         * @return true if packing successfully. Otherwise, return false.
+         */
+        boolean pack(AutoGrowByteBuffer output, T obj);
+
+        /**
+         * Return what kind of data is contained in the package.
+         */
+        default Class getMyType() {
+            return (Class) ((ParameterizedType) getClass().getGenericInterfaces()[0])
+                    .getActualTypeArguments()[0];
+        }
+    }
+
+    /*****************************************************************************************
+     * Following class are common {@link DataPackage} implementations, which include types
+     * that are defined in audio_utils::metadata::metadata_types
+     *
+     * For Java
+     *     int32_t corresponds to Integer
+     *     int64_t corresponds to Long
+     *     float corresponds to Float
+     *     double corresponds to Double
+     *     std::string corresponds to String
+     *     Data corresponds to BaseMap
+     *     Datum corresponds to Object
+     ****************************************************************************************/
+
+    private static final HashMap<Integer, DataPackage<?>> DATA_PACKAGES = new HashMap<>() {{
+            put(AUDIO_METADATA_OBJ_TYPE_INT, new DataPackage<Integer>() {
+                @Override
+                @Nullable
+                public Integer unpack(ByteBuffer buffer) {
+                    return buffer.getInt();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Integer obj) {
+                    output.putInt(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_LONG, new DataPackage<Long>() {
+                @Override
+                @Nullable
+                public Long unpack(ByteBuffer buffer) {
+                    return buffer.getLong();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Long obj) {
+                    output.putLong(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_FLOAT, new DataPackage<Float>() {
+                @Override
+                @Nullable
+                public Float unpack(ByteBuffer buffer) {
+                    return buffer.getFloat();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Float obj) {
+                    output.putFloat(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_DOUBLE, new DataPackage<Double>() {
+                @Override
+                @Nullable
+                public Double unpack(ByteBuffer buffer) {
+                    return buffer.getDouble();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Double obj) {
+                    output.putDouble(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_STRING, new DataPackage<String>() {
+                @Override
+                @Nullable
+                public String unpack(ByteBuffer buffer) {
+                    int dataSize = buffer.getInt();
+                    if (buffer.position() + dataSize > buffer.limit()) {
+                        return null;
+                    }
+                    byte[] valueArr = new byte[dataSize];
+                    buffer.get(valueArr);
+                    String value = new String(valueArr, AUDIO_METADATA_CHARSET);
+                    return value;
+                }
+
+                /**
+                 * This is a reversed operation of unpack. It is needed to write the String
+                 * at bytes encoded with AUDIO_METADATA_CHARSET. There should be an integer
+                 * value representing the length of the bytes written before the bytes.
+                 */
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, String obj) {
+                    byte[] valueArr = obj.getBytes(AUDIO_METADATA_CHARSET);
+                    output.putInt(valueArr.length);
+                    output.put(valueArr);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_BASEMAP, new BaseMapPackage());
+        }};
+    // ObjectPackage is a special case that it is expected to unpack audio_utils::metadata::Datum,
+    // which contains data type and data size besides the payload for the data.
+    private static final ObjectPackage OBJECT_PACKAGE = new ObjectPackage();
+
+    private static class ObjectPackage implements DataPackage<Pair<Class, Object>> {
+        /**
+         * The {@link ObjectPackage} will unpack byte string for audio_utils::metadata::Datum.
+         * Since the Datum is a std::any, {@link Object} is used to carrying the data. The
+         * data type is stored in the data package header. In that case, a {@link Class}
+         * will also be returned to indicate the actual type for the object.
+         */
+        @Override
+        @Nullable
+        public Pair<Class, Object> unpack(ByteBuffer buffer) {
+            int dataType = buffer.getInt();
+            DataPackage dataPackage = DATA_PACKAGES.get(dataType);
+            if (dataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
+                return null;
+            }
+            int dataSize = buffer.getInt();
+            int position = buffer.position();
+            Object obj = dataPackage.unpack(buffer);
+            if (buffer.position() - position != dataSize) {
+                Log.e(TAG, "Broken data package");
+                return null;
+            }
+            return new Pair<Class, Object>(dataPackage.getMyType(), obj);
+        }
+
+        @Override
+        public boolean pack(AutoGrowByteBuffer output, Pair<Class, Object> obj) {
+            final Integer dataType = AUDIO_METADATA_OBJ_TYPES.get(obj.first);
+            if (dataType == null) {
+                Log.e(TAG, "Cannot find data type for " + obj.first);
+                return false;
+            }
+            DataPackage dataPackage = DATA_PACKAGES.get(dataType);
+            if (dataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
+                return false;
+            }
+            output.putInt(dataType);
+            int position = output.position(); // Keep current position.
+            output.putInt(0); // Keep a place for the size of payload.
+            int payloadIdx = output.position();
+            if (!dataPackage.pack(output, obj.second)) {
+                Log.i(TAG, "Failed to pack object: " + obj.second);
+                return false;
+            }
+            // Put the actual payload size.
+            int currentPosition = output.position();
+            output.position(position);
+            output.putInt(currentPosition - payloadIdx);
+            output.position(currentPosition);
+            return true;
+        }
+    }
+
+    /**
+     * BaseMap will be corresponding to audio_utils::metadata::Data.
+     */
+    private static class BaseMapPackage implements DataPackage<BaseMap> {
+        @Override
+        @Nullable
+        public BaseMap unpack(ByteBuffer buffer) {
+            BaseMap ret = new BaseMap();
+            int mapSize = buffer.getInt();
+            DataPackage<String> strDataPackage =
+                    (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
+            if (strDataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for String");
+                return null;
+            }
+            for (int i = 0; i < mapSize; i++) {
+                String key = strDataPackage.unpack(buffer);
+                if (key == null) {
+                    Log.e(TAG, "Failed to unpack key for map");
+                    return null;
+                }
+                Pair<Class, Object> value = OBJECT_PACKAGE.unpack(buffer);
+                if (value == null) {
+                    Log.e(TAG, "Failed to unpack value for map");
+                    return null;
+                }
+                ret.set(createKey(key, value.first), value.first.cast(value.second));
+            }
+            return ret;
+        }
+
+        @Override
+        public boolean pack(AutoGrowByteBuffer output, BaseMap obj) {
+            output.putInt(obj.size());
+            DataPackage<String> strDataPackage =
+                    (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
+            if (strDataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for String");
+                return false;
+            }
+            for (Key<?> key : obj.keySet()) {
+                if (!strDataPackage.pack(output, key.getName())) {
+                    Log.i(TAG, "Failed to pack key: " + key.getName());
+                    return false;
+                }
+                if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), obj.get(key)))) {
+                    Log.i(TAG, "Failed to pack value: " + obj.get(key));
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * @hide
+     * Extract a {@link BaseMap} from a given {@link ByteBuffer}
+     * @param buffer is a byte string that contains information to unpack.
+     * @return a {@link BaseMap} object if extracting successfully from given byte buffer.
+     *     Otherwise, returns {@code null}.
+     */
+    @Nullable
+    public static BaseMap fromByteBuffer(ByteBuffer buffer) {
+        DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+        if (dataPackage == null) {
+            Log.e(TAG, "Cannot find DataPackage for BaseMap");
+            return null;
+        }
+        try {
+            return (BaseMap) dataPackage.unpack(buffer);
+        } catch (BufferUnderflowException e) {
+            Log.e(TAG, "No enough data to unpack");
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     * Pack a {link BaseMap} to a {@link ByteBuffer}
+     * @param data is the object for packing
+     * @param order is the byte order
+     * @return a {@link ByteBuffer} if successfully packing the data.
+     *     Otherwise, returns {@code null};
+     */
+    @Nullable
+    public static ByteBuffer toByteBuffer(BaseMap data, ByteOrder order) {
+        DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+        if (dataPackage == null) {
+            Log.e(TAG, "Cannot find DataPackage for BaseMap");
+            return null;
+        }
+        AutoGrowByteBuffer output = new AutoGrowByteBuffer();
+        output.order(order);
+        if (dataPackage.pack(output, data)) {
+            return output.getRawByteBuffer();
+        }
+        return null;
+    }
+
     // Delete the constructor as there is nothing to implement here.
     private AudioMetadata() {}
 }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 81275f6..94d4fcc 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -4050,8 +4050,15 @@
         }
 
         if (what == NATIVE_EVENT_CODEC_FORMAT_CHANGE) {
-            track.mCodecFormatChangedListeners.notify(
-                    0 /* eventCode, unused */, (AudioMetadata.ReadMap) obj);
+            ByteBuffer buffer = (ByteBuffer) obj;
+            buffer.order(ByteOrder.nativeOrder());
+            buffer.rewind();
+            AudioMetadata.ReadMap audioMetaData = AudioMetadata.fromByteBuffer(buffer);
+            if (audioMetaData == null) {
+                Log.e(TAG, "Unable to get audio metadata from byte buffer");
+                return;
+            }
+            track.mCodecFormatChangedListeners.notify(0 /* eventCode, unused */, audioMetaData);
             return;
         }
 
diff --git a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
index ab42d75..882caad 100644
--- a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
@@ -28,7 +28,6 @@
     // TODO: Change it to updateRoutes?
     void updateState(in MediaRoute2ProviderInfo providerInfo);
     void notifySessionCreated(in RoutingSessionInfo sessionInfo, long requestId);
-    void notifySessionCreationFailed(long requestId);
     void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
     void notifySessionReleased(in RoutingSessionInfo sessionInfo);
     void notifyRequestFailed(long requestId, int reason);
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index aa0eda1..51696a4 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -233,6 +233,7 @@
         String sessionId = sessionInfo.getId();
         synchronized (mSessionLock) {
             if (mSessionInfo.containsKey(sessionId)) {
+                // TODO: Notify failure to the requester, and throw exception if needed.
                 Log.w(TAG, "Ignoring duplicate session id.");
                 return;
             }
@@ -253,24 +254,6 @@
     }
 
     /**
-     * Notifies clients of that the session could not be created.
-     *
-     * @param requestId id of the previous request to create the session provided in
-     *                  {@link #onCreateSession(long, String, String, Bundle)}.
-     * @see #onCreateSession(long, String, String, Bundle)
-     */
-    public final void notifySessionCreationFailed(long requestId) {
-        if (mRemoteCallback == null) {
-            return;
-        }
-        try {
-            mRemoteCallback.notifySessionCreationFailed(requestId);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session creation failed.");
-        }
-    }
-
-    /**
      * Notifies the existing session is updated. For example, when
      * {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed.
      */
@@ -364,7 +347,7 @@
      * {@link Bundle} which contains how to control the session.
      * <p>
      * If you can't create the session or want to reject the request, call
-     * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
+     * {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
      *
      * @param requestId the id of this request
      * @param packageName the package name of the application that selected the route
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 734d78e..cf45328 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -304,13 +304,9 @@
      * @see Callback#onTransferFailed(RoutingSessionInfo, MediaRoute2Info)
      */
     public void transfer(@NonNull RoutingSessionInfo sessionInfo,
-            @Nullable MediaRoute2Info route) {
+            @NonNull MediaRoute2Info route) {
         Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
-
-        if (route == null) {
-            releaseSession(sessionInfo);
-            return;
-        }
+        Objects.requireNonNull(route, "route must not be null");
 
         //TODO: Ignore unknown route.
         if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
@@ -334,10 +330,10 @@
                 int requestId = mNextRequestId.getAndIncrement();
                 mMediaRouterService.requestCreateSessionWithManager(
                         client, sessionInfo.getClientPackageName(), route, requestId);
-                releaseSession(sessionInfo);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to select media route", ex);
             }
+            releaseSession(sessionInfo);
         }
     }
 
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index ffb26fe..629cf154 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -22,6 +22,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -73,10 +74,14 @@
         mClientPackageName = builder.mClientPackageName;
         mProviderId = builder.mProviderId;
 
-        mSelectedRoutes = Collections.unmodifiableList(builder.mSelectedRoutes);
-        mSelectableRoutes = Collections.unmodifiableList(builder.mSelectableRoutes);
-        mDeselectableRoutes = Collections.unmodifiableList(builder.mDeselectableRoutes);
-        mTransferableRoutes = Collections.unmodifiableList(builder.mTransferableRoutes);
+        mSelectedRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mSelectedRoutes));
+        mSelectableRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mSelectableRoutes));
+        mDeselectableRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mDeselectableRoutes));
+        mTransferableRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mTransferableRoutes));
 
         mVolumeHandling = builder.mVolumeHandling;
         mVolumeMax = builder.mVolumeMax;
@@ -326,6 +331,24 @@
         return result.toString();
     }
 
+    private List<String> convertToUniqueRouteIds(@NonNull List<String> routeIds) {
+        if (routeIds == null) {
+            Log.w(TAG, "routeIds is null. Returning an empty list");
+            return Collections.emptyList();
+        }
+
+        // mProviderId can be null if not set. Return the original list for this case.
+        if (mProviderId == null) {
+            return routeIds;
+        }
+
+        List<String> result = new ArrayList<>();
+        for (String routeId : routeIds) {
+            result.add(MediaRouter2Utils.toUniqueId(mProviderId, routeId));
+        }
+        return result;
+    }
+
     /**
      * Builder class for {@link RoutingSessionInfo}.
      */
@@ -345,7 +368,6 @@
         Bundle mControlHints;
         boolean mIsSystemSession;
 
-        //TODO: Remove this.
         /**
          * Constructor for builder to create {@link RoutingSessionInfo}.
          * <p>
@@ -392,6 +414,14 @@
             mDeselectableRoutes = new ArrayList<>(sessionInfo.mDeselectableRoutes);
             mTransferableRoutes = new ArrayList<>(sessionInfo.mTransferableRoutes);
 
+            if (mProviderId != null) {
+                // They must have unique IDs.
+                mSelectedRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+                mSelectableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+                mDeselectableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+                mTransferableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+            }
+
             mVolumeHandling = sessionInfo.mVolumeHandling;
             mVolumeMax = sessionInfo.mVolumeMax;
             mVolume = sessionInfo.mVolume;
@@ -431,12 +461,6 @@
                 throw new IllegalArgumentException("providerId must not be empty");
             }
             mProviderId = providerId;
-
-            mSelectedRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-            mSelectableRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-            mDeselectableRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-            mTransferableRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-
             return this;
         }
 
@@ -457,7 +481,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectedRoutes.add(getUniqueId(mProviderId, routeId));
+            mSelectedRoutes.add(routeId);
             return this;
         }
 
@@ -469,7 +493,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectedRoutes.remove(getUniqueId(mProviderId, routeId));
+            mSelectedRoutes.remove(routeId);
             return this;
         }
 
@@ -490,7 +514,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectableRoutes.add(getUniqueId(mProviderId, routeId));
+            mSelectableRoutes.add(routeId);
             return this;
         }
 
@@ -502,7 +526,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectableRoutes.remove(getUniqueId(mProviderId, routeId));
+            mSelectableRoutes.remove(routeId);
             return this;
         }
 
@@ -523,7 +547,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mDeselectableRoutes.add(getUniqueId(mProviderId, routeId));
+            mDeselectableRoutes.add(routeId);
             return this;
         }
 
@@ -535,7 +559,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mDeselectableRoutes.remove(getUniqueId(mProviderId, routeId));
+            mDeselectableRoutes.remove(routeId);
             return this;
         }
 
@@ -556,7 +580,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mTransferableRoutes.add(getUniqueId(mProviderId, routeId));
+            mTransferableRoutes.add(routeId);
             return this;
         }
 
@@ -568,7 +592,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mTransferableRoutes.remove(getUniqueId(mProviderId, routeId));
+            mTransferableRoutes.remove(routeId);
             return this;
         }
 
@@ -634,15 +658,4 @@
             return new RoutingSessionInfo(this);
         }
     }
-
-    private static String getUniqueId(String providerId, String routeId) {
-        if (TextUtils.isEmpty(providerId)) {
-            return routeId;
-        }
-        String originalId = MediaRouter2Utils.getOriginalId(routeId);
-        if (originalId == null) {
-            originalId = routeId;
-        }
-        return MediaRouter2Utils.toUniqueId(providerId, originalId);
-    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 064ab80..7b29494 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -34,6 +34,27 @@
  */
 @SystemApi
 public class AlpFilterConfiguration extends FilterConfiguration {
+    /**
+     * IPv4 packet type.
+     */
+    public static final int PACKET_TYPE_IPV4 = 0;
+    /**
+     * Compressed packet type.
+     */
+    public static final int PACKET_TYPE_COMPRESSED = 2;
+    /**
+     * Signaling packet type.
+     */
+    public static final int PACKET_TYPE_SIGNALING = 4;
+    /**
+     * Extension packet type.
+     */
+    public static final int PACKET_TYPE_EXTENSION = 6;
+    /**
+     * MPEG-2 TS packet type.
+     */
+    public static final int PACKET_TYPE_MPEG2_TS = 7;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "LENGTH_TYPE_", value =
@@ -73,8 +94,9 @@
 
     /**
      * Gets packet type.
+     *
+     * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
      */
-    @FilterConfiguration.PacketType
     public int getPacketType() {
         return mPacketType;
     }
@@ -110,9 +132,11 @@
 
         /**
          * Sets packet type.
+         *
+         * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
          */
         @NonNull
-        public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+        public Builder setPacketType(int packetType) {
             mPacketType = packetType;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index cfb943b..52bdb59 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -45,6 +45,10 @@
     public @interface Type {}
 
     /**
+     * Undefined filter type.
+     */
+    public static final int TYPE_UNDEFINED = 0;
+    /**
      * TS filter type.
      */
     public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
@@ -248,7 +252,6 @@
     /**
      * Gets the filter Id.
      */
-    @Result
     public int getId() {
         return nativeGetId();
     }
@@ -273,6 +276,8 @@
     /**
      * Starts filtering data.
      *
+     * <p>Does nothing if the filter is already started.
+     *
      * @return result status of the operation.
      */
     @Result
@@ -284,6 +289,8 @@
     /**
      * Stops filtering data.
      *
+     * <p>Does nothing if the filter is stopped or not started.
+     *
      * @return result status of the operation.
      */
     @Result
@@ -312,14 +319,13 @@
      * @param size the maximum number of bytes to read.
      * @return the number of bytes read.
      */
-    @Result
     public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
         size = Math.min(size, buffer.length - offset);
         return nativeRead(buffer, offset, size);
     }
 
     /**
-     * Releases the Filter instance.
+     * Stops filtering data and releases the Filter instance.
      */
     @Override
     public void close() {
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index c1d2275..a8c9356 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -16,14 +16,10 @@
 
 package android.media.tv.tuner.filter;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Filter configuration used to configure filters.
  *
@@ -32,26 +28,6 @@
 @SystemApi
 public abstract class FilterConfiguration {
 
-    /** @hide */
-    @IntDef(prefix = "PACKET_TYPE_", value =
-            {PACKET_TYPE_IPV4, PACKET_TYPE_COMPRESSED, PACKET_TYPE_SIGNALING})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface PacketType {}
-
-    /**
-     * IP v4 packet type.
-     */
-    public static final int PACKET_TYPE_IPV4 = 0;
-    /**
-     * Compressed packet type.
-     */
-    public static final int PACKET_TYPE_COMPRESSED = 2;
-    /**
-     * Signaling packet type.
-     */
-    public static final int PACKET_TYPE_SIGNALING = 4;
-
-
     @Nullable
     /* package */ final Settings mSettings;
 
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index 3d83a74..ac4fc83 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -29,6 +29,27 @@
  */
 @SystemApi
 public class TlvFilterConfiguration extends FilterConfiguration {
+    /**
+     * IPv4 packet type.
+     */
+    public static final int PACKET_TYPE_IPV4 = 0x01;
+    /**
+     * IPv6 packet type.
+     */
+    public static final int PACKET_TYPE_IPV6 = 0x02;
+    /**
+     * Compressed packet type.
+     */
+    public static final int PACKET_TYPE_COMPRESSED = 0x03;
+    /**
+     * Signaling packet type.
+     */
+    public static final int PACKET_TYPE_SIGNALING = 0xFE;
+    /**
+     * NULL packet type.
+     */
+    public static final int PACKET_TYPE_NULL = 0xFF;
+
     private final int mPacketType;
     private final boolean mIsCompressedIpPacket;
     private final boolean mPassthrough;
@@ -48,8 +69,9 @@
 
     /**
      * Gets packet type.
+     *
+     * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
      */
-    @FilterConfiguration.PacketType
     public int getPacketType() {
         return mPacketType;
     }
@@ -96,9 +118,11 @@
 
         /**
          * Sets packet type.
+         *
+         * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
          */
         @NonNull
-        public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+        public Builder setPacketType(int packetType) {
             mPacketType = packetType;
             return this;
         }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
index 2230e25..31f240d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
@@ -70,7 +70,7 @@
 
         RoutingSessionInfo sessionInfoWithOtherProviderId =
                 new RoutingSessionInfo.Builder(sessionInfoWithProviderId)
-                .setProviderId(TEST_OTHER_PROVIDER_ID).build();
+                        .setProviderId(TEST_OTHER_PROVIDER_ID).build();
 
         assertNotEquals(sessionInfoWithOtherProviderId.getSelectedRoutes(),
                 sessionInfoWithProviderId.getSelectedRoutes());
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 0e7c7fc..22c5bce 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -216,8 +216,7 @@
             @Nullable Bundle sessionHints) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
-            // Tell the router that session cannot be created by passing null as sessionInfo.
-            notifySessionCreationFailed(requestId);
+            notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
             return;
         }
         maybeDeselectRoute(routeId);
diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
index 2fe9d21..55207b3 100644
--- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -16,6 +16,7 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fullscreen_user_switcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:fitsSystemWindows="true">
@@ -24,22 +25,26 @@
         android:id="@+id/container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:layout_alignParentTop="true"
         android:orientation="vertical">
 
-        <include
-            layout="@layout/car_status_bar_header"
-            android:layout_alignParentTop="true"
-            android:theme="@android:style/Theme"/>
+        <!-- TODO(b/150302361): Status bar is commented out since a top inset is being added which causes it to be displayed below the top of the screen. -->
+        <!--        <include
+                    layout="@layout/car_status_bar_header"
+                    android:layout_alignParentTop="true"
+                    android:theme="@android:style/Theme"/>-->
+
 
         <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent">
-            <com.android.systemui.statusbar.car.UserGridRecyclerView
+            <com.android.systemui.car.userswitcher.UserGridRecyclerView
                 android:id="@+id/user_grid"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>
+                android:layout_gravity="center_vertical"/>
+            <!-- TODO(b/150302361): Re-add marginTop once status bar has been added back. -->
+            <!--                android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>-->
         </FrameLayout>
 
     </LinearLayout>
diff --git a/packages/CarSystemUI/res/layout/car_qs_panel.xml b/packages/CarSystemUI/res/layout/car_qs_panel.xml
index 9c598d7..0c6f322 100644
--- a/packages/CarSystemUI/res/layout/car_qs_panel.xml
+++ b/packages/CarSystemUI/res/layout/car_qs_panel.xml
@@ -33,7 +33,7 @@
         android:layout_width="match_parent"
         android:layout_height="@dimen/car_user_switcher_container_height">
 
-        <com.android.systemui.statusbar.car.UserGridRecyclerView
+        <com.android.systemui.car.userswitcher.UserGridRecyclerView
             android:id="@+id/user_grid"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>
diff --git a/packages/CarSystemUI/res/layout/sysui_primary_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
similarity index 100%
rename from packages/CarSystemUI/res/layout/sysui_primary_window.xml
rename to packages/CarSystemUI/res/layout/sysui_overlay_window.xml
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 825b281..aaa65de 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -58,6 +58,11 @@
         to a constant alpha percent value using the initial alpha. -->
     <integer name="config_finalNotificationBackgroundAlpha">100</integer>
 
+    <!-- Car System UI's OverlayViewsMediator-->
+    <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
+        <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
+    </string-array>
+
     <!-- SystemUI Services: The classes of the stuff to start. -->
     <string-array name="config_systemUIServiceComponents" translatable="false">
         <item>com.android.systemui.util.NotificationChannels</item>
@@ -85,5 +90,6 @@
         <item>com.android.systemui.navigationbar.car.CarNavigationBar</item>
         <item>com.android.systemui.toast.ToastUI</item>
         <item>com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier</item>
+        <item>com.android.systemui.window.SystemUIOverlayWindowManager</item>
     </string-array>
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 8f9d7ed..c010881 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -39,6 +39,8 @@
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier;
 import com.android.systemui.volume.VolumeUI;
+import com.android.systemui.window.OverlayWindowModule;
+import com.android.systemui.window.SystemUIOverlayWindowManager;
 
 import dagger.Binds;
 import dagger.Module;
@@ -47,7 +49,7 @@
 
 /** Binder for car specific {@link SystemUI} modules. */
 @Module(includes = {RecentsModule.class, CarStatusBarModule.class, NotificationsModule.class,
-        BubbleModule.class, KeyguardModule.class})
+        BubbleModule.class, KeyguardModule.class, OverlayWindowModule.class})
 public abstract class CarSystemUIBinder {
     /** Inject into AuthController. */
     @Binds
@@ -182,4 +184,10 @@
     @ClassKey(ConnectedDeviceVoiceRecognitionNotifier.class)
     public abstract SystemUI bindConnectedDeviceVoiceRecognitionNotifier(
             ConnectedDeviceVoiceRecognitionNotifier sysui);
+
+    /** Inject into SystemUIOverlayWindowManager. */
+    @Binds
+    @IntoMap
+    @ClassKey(SystemUIOverlayWindowManager.class)
+    public abstract SystemUI bindSystemUIPrimaryWindowManager(SystemUIOverlayWindowManager sysui);
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java
similarity index 98%
rename from packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
rename to packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java
index 07dbd66..5977165 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.car;
+package com.android.systemui.car.userswitcher;
 
 import android.app.admin.DevicePolicyManager;
 import android.bluetooth.BluetoothAdapter;
@@ -56,8 +56,8 @@
     private final UserManager mUserManager;
     private final WindowManager.LayoutParams mParams;
     /**
-     * Not using Dialog because context passed from {@link FullscreenUserSwitcher} is not an
-     * activity.
+     * Not using Dialog because context passed from {@link FullscreenUserSwitcherViewMediator}
+     * is not an activity.
      */
     private final View mUnlockDialogLayout;
     private final TextView mUnlockingText;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java
new file mode 100644
index 0000000..45ceb6d
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.window.OverlayViewController;
+import com.android.systemui.window.OverlayViewGlobalStateController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controller for {@link R.layout#car_fullscreen_user_switcher}.
+ */
+@Singleton
+public class FullScreenUserSwitcherViewController extends OverlayViewController {
+    private final Context mContext;
+    private final Resources mResources;
+    private final int mShortAnimationDuration;
+    private UserGridRecyclerView mUserGridView;
+    private UserGridRecyclerView.UserSelectionListener mUserSelectionListener;
+
+    @Inject
+    public FullScreenUserSwitcherViewController(
+            Context context,
+            @Main Resources resources,
+            OverlayViewGlobalStateController overlayViewGlobalStateController) {
+        super(R.id.fullscreen_user_switcher_stub, overlayViewGlobalStateController);
+        mContext = context;
+        mResources = resources;
+        mShortAnimationDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        // Initialize user grid.
+        mUserGridView = getLayout().findViewById(R.id.user_grid);
+        GridLayoutManager layoutManager = new GridLayoutManager(mContext,
+                mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
+        mUserGridView.setLayoutManager(layoutManager);
+        mUserGridView.buildAdapter();
+        mUserGridView.setUserSelectionListener(mUserSelectionListener);
+    }
+
+    @Override
+    protected void showInternal() {
+        getLayout().setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    protected void hideInternal() {
+        // Switching is about to happen, since it takes time, fade out the switcher gradually.
+        fadeOut();
+    }
+
+    private void fadeOut() {
+        mUserGridView.animate()
+                .alpha(0.0f)
+                .setDuration(mShortAnimationDuration)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        getLayout().setVisibility(View.GONE);
+                        mUserGridView.setAlpha(1.0f);
+                    }
+                });
+
+    }
+
+    /**
+     * Invalidate underlying view.
+     */
+    void invalidate() {
+        if (getLayout() == null) {
+            // layout hasn't been inflated.
+            return;
+        }
+
+        getLayout().invalidate();
+    }
+
+    /**
+     * Set {@link UserGridRecyclerView.UserSelectionListener}.
+     */
+    void setUserGridSelectionListener(
+            UserGridRecyclerView.UserSelectionListener userGridSelectionListener) {
+        mUserSelectionListener = userGridSelectionListener;
+    }
+
+    /**
+     * Returns {@code true} when layout is visible.
+     */
+    boolean isVisible() {
+        if (getLayout() == null) {
+            // layout hasn't been inflated.
+            return false;
+        }
+
+        return getLayout().getVisibility() == View.VISIBLE;
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
new file mode 100644
index 0000000..6277297
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import android.car.Car;
+import android.car.trust.CarTrustAgentEnrollmentManager;
+import android.car.userlib.CarUserManagerHelper;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.car.CarStatusBar;
+import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
+import com.android.systemui.window.OverlayViewMediator;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages the fullscreen user switcher and it's interactions with the keyguard.
+ */
+@Singleton
+public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
+    private static final String TAG = FullscreenUserSwitcherViewMediator.class.getSimpleName();
+
+    private final Context mContext;
+    private final UserManager mUserManager;
+    private final CarServiceProvider mCarServiceProvider;
+    private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
+    private final CarStatusBarKeyguardViewManager mCarStatusBarKeyguardViewManager;
+    private final Handler mMainHandler;
+    private final StatusBarStateController mStatusBarStateController;
+    private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController;
+    private final ScreenLifecycle mScreenLifecycle;
+    private final CarStatusBar mCarStatusBar;
+    private final boolean mIsUserSwitcherEnabled;
+    private final CarUserManagerHelper mCarUserManagerHelper;
+
+    private CarTrustAgentEnrollmentManager mEnrollmentManager;
+    private UserGridRecyclerView.UserRecord mSelectedUser;
+    private final CarTrustAgentUnlockDialogHelper.OnHideListener mOnHideListener =
+            dismissUserSwitcher -> {
+                if (dismissUserSwitcher) {
+                    dismissUserSwitcher();
+                } else {
+                    // Re-draw the parent view, otherwise the unlock dialog will not be removed
+                    // from the screen immediately.
+                    invalidateFullscreenUserSwitcherView();
+                }
+            };
+    private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible.");
+            }
+            showDialogForInitialUser();
+            mContext.unregisterReceiver(mUserUnlockReceiver);
+        }
+    };
+
+    @Inject
+    public FullscreenUserSwitcherViewMediator(
+            Context context,
+            @Main Resources resources,
+            @Main Handler mainHandler,
+            UserManager userManager,
+            CarServiceProvider carServiceProvider,
+            CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper,
+            CarStatusBarKeyguardViewManager carStatusBarKeyguardViewManager,
+            CarStatusBar carStatusBar,
+            StatusBarStateController statusBarStateController,
+            FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController,
+            ScreenLifecycle screenLifecycle) {
+        mContext = context;
+
+        mIsUserSwitcherEnabled = resources.getBoolean(R.bool.config_enableFullscreenUserSwitcher);
+
+        mMainHandler = mainHandler;
+        mUserManager = userManager;
+
+        mCarServiceProvider = carServiceProvider;
+        mCarServiceProvider.addListener(
+                car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
+                        Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
+
+        mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
+        mCarStatusBarKeyguardViewManager = carStatusBarKeyguardViewManager;
+        mCarStatusBar = carStatusBar;
+        mStatusBarStateController = statusBarStateController;
+        mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
+        mScreenLifecycle = screenLifecycle;
+
+        mCarUserManagerHelper = new CarUserManagerHelper(mContext);
+    }
+
+    @Override
+    public void registerListeners() {
+        registerUserSwitcherShowListeners();
+        registerUserSwitcherHideListeners();
+        registerHideKeyguardListeners();
+
+        if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
+            // User0 is unlocked, switched to the initial user
+            showDialogForInitialUser();
+        } else {
+            // listen to USER_UNLOCKED
+            mContext.registerReceiverAsUser(mUserUnlockReceiver,
+                    UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM),
+                    new IntentFilter(Intent.ACTION_USER_UNLOCKED),
+                    /* broadcastPermission= */ null,
+                    /* scheduler= */ null);
+        }
+    }
+
+    private void registerUserSwitcherShowListeners() {
+        mCarStatusBarKeyguardViewManager.addOnKeyguardCancelClickedListener(this::show);
+    }
+
+    private void registerUserSwitcherHideListeners() {
+        mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+            @Override
+            public void onStateChanged(int newState) {
+                if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+                    return;
+                }
+                hide();
+            }
+        });
+    }
+
+    private void registerHideKeyguardListeners() {
+        mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+            @Override
+            public void onStateChanged(int newState) {
+                if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) {
+                    return;
+                }
+                dismissKeyguardWhenUserSwitcherNotDisplayed(newState);
+            }
+        });
+
+        mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() {
+            @Override
+            public void onScreenTurnedOn() {
+                dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState());
+            }
+        });
+
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (!intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
+                    return;
+                }
+
+                // Try to dismiss the keyguard after every user switch.
+                dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState());
+            }
+        }, new IntentFilter(Intent.ACTION_USER_SWITCHED));
+    }
+
+    @Override
+    public void setupOverlayContentViewControllers() {
+        mFullScreenUserSwitcherViewController.setUserGridSelectionListener(this::onUserSelected);
+    }
+
+    /**
+     * Every time user clicks on an item in the switcher, if the clicked user has no trusted
+     * device, we hide the switcher, either gradually or immediately.
+     * If the user has trusted device, we show an unlock dialog to notify user the unlock
+     * state.
+     * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher.
+     * We dismiss the entire keyguard when we hide the switcher if user clicked on the
+     * foreground user (user we're already logged in as).
+     */
+    private void onUserSelected(UserGridRecyclerView.UserRecord record) {
+        mSelectedUser = record;
+        if (record.mInfo != null) {
+            if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
+                mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
+                return;
+            }
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
+            }
+        }
+        dismissUserSwitcher();
+    }
+
+    // We automatically dismiss keyguard unless user switcher is being shown above the keyguard.
+    private void dismissKeyguardWhenUserSwitcherNotDisplayed(int state) {
+        if (!mIsUserSwitcherEnabled) {
+            return; // Not using the full screen user switcher.
+        }
+
+        if (state == StatusBarState.FULLSCREEN_USER_SWITCHER
+                && !mFullScreenUserSwitcherViewController.isVisible()) {
+            // Current execution path continues to set state after this, thus we deffer the
+            // dismissal to the next execution cycle.
+
+            // Dismiss the keyguard if switcher is not visible.
+            // TODO(b/150402329): Remove once keyguard is implemented using Overlay Window
+            //  abstractions.
+            mMainHandler.post(mCarStatusBar::dismissKeyguard);
+        }
+    }
+
+    private boolean hasScreenLock(int uid) {
+        LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+        return lockPatternUtils.getCredentialTypeForUser(uid)
+                != LockPatternUtils.CREDENTIAL_TYPE_NONE;
+    }
+
+    private boolean hasTrustedDevice(int uid) {
+        if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
+            return false;
+        }
+        return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
+    }
+
+    private void dismissUserSwitcher() {
+        if (mSelectedUser == null) {
+            Log.e(TAG, "Request to dismiss user switcher, but no user selected");
+            return;
+        }
+        if (mSelectedUser.mType == UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
+            hide();
+            mCarStatusBar.dismissKeyguard();
+            return;
+        }
+        hide();
+    }
+
+    private void showDialogForInitialUser() {
+        int initialUser = mCarUserManagerHelper.getInitialUser();
+        UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
+        mSelectedUser = new UserGridRecyclerView.UserRecord(initialUserInfo,
+                UserGridRecyclerView.UserRecord.FOREGROUND_USER);
+
+        // If the initial user has screen lock and trusted device, display the unlock dialog on the
+        // keyguard.
+        if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) {
+            mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
+                    mOnHideListener);
+        } else {
+            // If no trusted device, dismiss the keyguard.
+            dismissUserSwitcher();
+        }
+    }
+
+    private void invalidateFullscreenUserSwitcherView() {
+        mFullScreenUserSwitcherViewController.invalidate();
+    }
+
+    private void hide() {
+        mFullScreenUserSwitcherViewController.stop();
+    }
+
+    private void show() {
+        mFullScreenUserSwitcherViewController.start();
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
similarity index 97%
rename from packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
rename to packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
index 7dd3be4..58add17 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.car;
+package com.android.systemui.car.userswitcher;
 
 import static android.content.DialogInterface.BUTTON_NEGATIVE;
 import static android.content.DialogInterface.BUTTON_POSITIVE;
@@ -45,7 +45,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
-import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -114,8 +113,6 @@
 
     /**
      * Initializes the adapter that populates the grid layout
-     *
-     * @return the adapter
      */
     public void buildAdapter() {
         List<UserRecord> userRecords = createUserRecords(getUsersForUserGrid());
@@ -236,10 +233,16 @@
             mNewUserName = mRes.getString(R.string.car_new_user);
         }
 
+        /**
+         * Clears list of user records.
+         */
         public void clearUsers() {
             mUsers.clear();
         }
 
+        /**
+         * Updates list of user records.
+         */
         public void updateUsers(List<UserRecord> users) {
             mUsers = users;
         }
@@ -483,6 +486,10 @@
             return mUsers.size();
         }
 
+        /**
+         * An extension of {@link RecyclerView.ViewHolder} that also houses the user name and the
+         * user avatar.
+         */
         public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
 
             public ImageView mUserAvatarImageView;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
similarity index 97%
rename from packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
rename to packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
index 9018290..dc5953e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.car;
+package com.android.systemui.car.userswitcher;
 
 import android.annotation.UserIdInt;
 import android.content.Context;
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
index a56c4ed..67e9da4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
@@ -71,6 +71,30 @@
         mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
     }
 
+    /**
+     * Hides all navigation bars.
+     */
+    public void hideBars() {
+        if (mTopView != null) {
+            mTopView.setVisibility(View.GONE);
+        }
+        setBottomWindowVisibility(View.GONE);
+        setLeftWindowVisibility(View.GONE);
+        setRightWindowVisibility(View.GONE);
+    }
+
+    /**
+     * Shows all navigation bars.
+     */
+    public void showBars() {
+        if (mTopView != null) {
+            mTopView.setVisibility(View.VISIBLE);
+        }
+        setBottomWindowVisibility(View.VISIBLE);
+        setLeftWindowVisibility(View.VISIBLE);
+        setRightWindowVisibility(View.VISIBLE);
+    }
+
     /** Connect to hvac service. */
     public void connectToHvac() {
         mHvacControllerLazy.get().connectToCarService();
diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index f9cfafa..31965c5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -35,9 +35,9 @@
 import androidx.recyclerview.widget.GridLayoutManager;
 
 import com.android.systemui.R;
+import com.android.systemui.car.userswitcher.UserGridRecyclerView;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFooter;
-import com.android.systemui.statusbar.car.UserGridRecyclerView;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 0374a5c..83248f4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -67,7 +67,6 @@
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedListener;
 import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.SystemUIPrimaryWindowController;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -95,7 +94,6 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
@@ -181,14 +179,13 @@
     private Drawable mNotificationPanelBackground;
 
     private final Object mQueueLock = new Object();
-    private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController;
     private final CarNavigationBarController mCarNavigationBarController;
     private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
     private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
-    private final FullscreenUserSwitcher mFullscreenUserSwitcher;
     private final ShadeController mShadeController;
     private final CarServiceProvider mCarServiceProvider;
     private final CarDeviceProvisionedController mCarDeviceProvisionedController;
+    private final ScreenLifecycle mScreenLifecycle;
 
     private boolean mDeviceIsSetUpForUser = true;
     private boolean mIsUserSetupInProgress = false;
@@ -196,7 +193,6 @@
     private FlingAnimationUtils mFlingAnimationUtils;
     private NotificationDataManager mNotificationDataManager;
     private NotificationClickHandlerFactory mNotificationClickHandlerFactory;
-    private ScreenLifecycle mScreenLifecycle;
 
     // The container for the notifications.
     private CarNotificationView mNotificationView;
@@ -333,8 +329,6 @@
             /* Car Settings injected components. */
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
-            FullscreenUserSwitcher fullscreenUserSwitcher,
-            SystemUIPrimaryWindowController systemUIPrimaryWindowController,
             CarNavigationBarController carNavigationBarController,
             FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
         super(
@@ -423,10 +417,9 @@
         mShadeController = shadeController;
         mCarServiceProvider = carServiceProvider;
         mPowerManagerHelperLazy = powerManagerHelperLazy;
-        mFullscreenUserSwitcher = fullscreenUserSwitcher;
-        mSystemUIPrimaryWindowController = systemUIPrimaryWindowController;
         mCarNavigationBarController = carNavigationBarController;
         mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
+        mScreenLifecycle = screenLifecycle;
     }
 
     @Override
@@ -434,18 +427,6 @@
         mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
         mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
 
-        // Need to initialize screen lifecycle before calling super.start - before switcher is
-        // created.
-        mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
-        mScreenLifecycle.addObserver(mScreenObserver);
-
-        // TODO: Remove the setup of user switcher from Car Status Bar.
-        mSystemUIPrimaryWindowController.attach();
-        mFullscreenUserSwitcher.setStatusBar(this);
-        mFullscreenUserSwitcher.setContainer(
-                mSystemUIPrimaryWindowController.getBaseLayout().findViewById(
-                        R.id.fullscreen_user_switcher_stub));
-
         // Notification bar related setup.
         mInitialBackgroundAlpha = (float) mContext.getResources().getInteger(
                 R.integer.config_initialNotificationBackgroundAlpha) / 100;
@@ -965,49 +946,6 @@
         }
     }
 
-    @Override
-    public void setLockscreenUser(int newUserId) {
-        super.setLockscreenUser(newUserId);
-        // Try to dismiss the keyguard after every user switch.
-        dismissKeyguardWhenUserSwitcherNotDisplayed();
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        super.onStateChanged(newState);
-
-        if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) {
-            mFullscreenUserSwitcher.hide();
-        } else {
-            dismissKeyguardWhenUserSwitcherNotDisplayed();
-        }
-    }
-
-    final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
-        @Override
-        public void onScreenTurnedOn() {
-            dismissKeyguardWhenUserSwitcherNotDisplayed();
-        }
-    };
-
-    // We automatically dismiss keyguard unless user switcher is being shown on the keyguard.
-    private void dismissKeyguardWhenUserSwitcherNotDisplayed() {
-        if (!mUserSwitcherController.useFullscreenUserSwitcher()) {
-            return; // Not using the full screen user switcher.
-        }
-
-        if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER
-                && !mFullscreenUserSwitcher.isVisible()) {
-            // Current execution path continues to set state after this, thus we deffer the
-            // dismissal to the next execution cycle.
-            postDismissKeyguard(); // Dismiss the keyguard if switcher is not visible.
-        }
-    }
-
-    public void postDismissKeyguard() {
-        mHandler.post(this::dismissKeyguard);
-    }
-
     /**
      * Dismisses the keyguard and shows bouncer if authentication is necessary.
      */
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
index 59f9f94..e1c051f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
@@ -33,6 +33,9 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -42,7 +45,7 @@
 
     protected boolean mShouldHideNavBar;
     private final CarNavigationBarController mCarNavigationBarController;
-    private final FullscreenUserSwitcher mFullscreenUserSwitcher;
+    private Set<OnKeyguardCancelClickedListener> mKeygaurdCancelClickedListenerSet;
 
     @Inject
     public CarStatusBarKeyguardViewManager(Context context,
@@ -56,8 +59,7 @@
             NotificationShadeWindowController notificationShadeWindowController,
             KeyguardStateController keyguardStateController,
             NotificationMediaManager notificationMediaManager,
-            CarNavigationBarController carNavigationBarController,
-            FullscreenUserSwitcher fullscreenUserSwitcher) {
+            CarNavigationBarController carNavigationBarController) {
         super(context, callback, lockPatternUtils, sysuiStatusBarStateController,
                 configurationController, keyguardUpdateMonitor, navigationModeController,
                 dockManager, notificationShadeWindowController, keyguardStateController,
@@ -65,7 +67,7 @@
         mShouldHideNavBar = context.getResources()
                 .getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown);
         mCarNavigationBarController = carNavigationBarController;
-        mFullscreenUserSwitcher = fullscreenUserSwitcher;
+        mKeygaurdCancelClickedListenerSet = new HashSet<>();
     }
 
     @Override
@@ -95,7 +97,7 @@
      */
     @Override
     public void onCancelClicked() {
-        mFullscreenUserSwitcher.show();
+        mKeygaurdCancelClickedListenerSet.forEach(OnKeyguardCancelClickedListener::onCancelClicked);
     }
 
     /**
@@ -105,4 +107,31 @@
      */
     @Override
     public void onDensityOrFontScaleChanged() {  }
+
+    /**
+     * Add listener for keyguard cancel clicked.
+     */
+    public void addOnKeyguardCancelClickedListener(
+            OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
+        mKeygaurdCancelClickedListenerSet.add(keyguardCancelClickedListener);
+    }
+
+    /**
+     * Remove listener for keyguard cancel clicked.
+     */
+    public void removeOnKeyguardCancelClickedListener(
+            OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
+        mKeygaurdCancelClickedListenerSet.remove(keyguardCancelClickedListener);
+    }
+
+
+    /**
+     * Defines a callback for keyguard cancel button clicked listeners.
+     */
+    public interface OnKeyguardCancelClickedListener {
+        /**
+         * Called when keyguard cancel button is clicked.
+         */
+        void onCancelClicked();
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 07c42e1..aea4bd4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -31,7 +31,6 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.SystemUIPrimaryWindowController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -205,8 +204,6 @@
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
-            FullscreenUserSwitcher fullscreenUserSwitcher,
-            SystemUIPrimaryWindowController systemUIPrimaryWindowController,
             CarNavigationBarController carNavigationBarController,
             FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
         return new CarStatusBar(
@@ -288,8 +285,6 @@
                 statusBarTouchableRegionManager,
                 carServiceProvider,
                 powerManagerHelperLazy,
-                fullscreenUserSwitcher,
-                systemUIPrimaryWindowController,
                 carNavigationBarController,
                 flingAnimationUtilsBuilder);
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
deleted file mode 100644
index 3cd66c2..0000000
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.car;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.car.Car;
-import android.car.trust.CarTrustAgentEnrollmentManager;
-import android.car.userlib.CarUserManagerHelper;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewStub;
-
-import androidx.recyclerview.widget.GridLayoutManager;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.R;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.SystemUIPrimaryWindowController;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener;
-import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Manages the fullscreen user switcher.
- */
-@Singleton
-public class FullscreenUserSwitcher {
-    private static final String TAG = FullscreenUserSwitcher.class.getSimpleName();
-    private final Context mContext;
-    private final Resources mResources;
-    private final UserManager mUserManager;
-    private final CarServiceProvider mCarServiceProvider;
-    private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
-    private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController;
-    private CarStatusBar mCarStatusBar;
-    private final int mShortAnimDuration;
-
-    private View mParent;
-    private UserGridRecyclerView mUserGridView;
-    private CarTrustAgentEnrollmentManager mEnrollmentManager;
-    private UserGridRecyclerView.UserRecord mSelectedUser;
-    private CarUserManagerHelper mCarUserManagerHelper;
-    private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible.");
-            }
-            showDialogForInitialUser();
-            mContext.unregisterReceiver(mUserUnlockReceiver);
-        }
-    };
-
-    @Inject
-    public FullscreenUserSwitcher(
-            Context context,
-            @Main Resources resources,
-            UserManager userManager,
-            CarServiceProvider carServiceProvider,
-            CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper,
-            SystemUIPrimaryWindowController systemUIPrimaryWindowController) {
-        mContext = context;
-        mResources = resources;
-        mUserManager = userManager;
-        mCarServiceProvider = carServiceProvider;
-        mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
-        mSystemUIPrimaryWindowController = systemUIPrimaryWindowController;
-
-        mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
-    }
-
-    /** Sets the status bar which gives an entry point to dismiss the keyguard. */
-    // TODO: Remove this in favor of a keyguard controller.
-    public void setStatusBar(CarStatusBar statusBar) {
-        mCarStatusBar = statusBar;
-    }
-
-    /** Returns {@code true} if the user switcher already has a parent view. */
-    public boolean isAttached() {
-        return mParent != null;
-    }
-
-    /** Sets the {@link ViewStub} to show the user switcher. */
-    public void setContainer(ViewStub containerStub) {
-        if (isAttached()) {
-            return;
-        }
-
-        mParent = containerStub.inflate();
-
-        View container = mParent.findViewById(R.id.container);
-
-        // Initialize user grid.
-        mUserGridView = container.findViewById(R.id.user_grid);
-        GridLayoutManager layoutManager = new GridLayoutManager(mContext,
-                mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
-        mUserGridView.setLayoutManager(layoutManager);
-        mUserGridView.buildAdapter();
-        mUserGridView.setUserSelectionListener(this::onUserSelected);
-        mCarUserManagerHelper = new CarUserManagerHelper(mContext);
-        mCarServiceProvider.addListener(
-                car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
-                        Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
-
-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
-        if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
-            // User0 is unlocked, switched to the initial user
-            showDialogForInitialUser();
-        } else {
-            // listen to USER_UNLOCKED
-            mContext.registerReceiverAsUser(mUserUnlockReceiver,
-                    UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM),
-                    filter,
-                    /* broadcastPermission= */ null,
-                    /* scheduler */ null);
-        }
-    }
-
-    private void showDialogForInitialUser() {
-        int initialUser = mCarUserManagerHelper.getInitialUser();
-        UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
-        mSelectedUser = new UserRecord(initialUserInfo, UserRecord.FOREGROUND_USER);
-
-        // If the initial user has screen lock and trusted device, display the unlock dialog on the
-        // keyguard.
-        if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) {
-            mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
-                    mOnHideListener);
-        } else {
-            // If no trusted device, dismiss the keyguard.
-            dismissUserSwitcher();
-        }
-    }
-
-    /**
-     * Makes user grid visible.
-     */
-    public void show() {
-        if (!isAttached()) {
-            return;
-        }
-        mParent.setVisibility(View.VISIBLE);
-        mSystemUIPrimaryWindowController.setWindowExpanded(true);
-    }
-
-    /**
-     * Hides the user grid.
-     */
-    public void hide() {
-        if (!isAttached()) {
-            return;
-        }
-        mParent.setVisibility(View.INVISIBLE);
-        mSystemUIPrimaryWindowController.setWindowExpanded(false);
-    }
-
-    /**
-     * @return {@code true} if user grid is visible, {@code false} otherwise.
-     */
-    public boolean isVisible() {
-        if (!isAttached()) {
-            return false;
-        }
-        return mParent.getVisibility() == View.VISIBLE;
-    }
-
-    /**
-     * Every time user clicks on an item in the switcher, if the clicked user has no trusted device,
-     * we hide the switcher, either gradually or immediately.
-     *
-     * If the user has trusted device, we show an unlock dialog to notify user the unlock state.
-     * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher.
-     *
-     * We dismiss the entire keyguard when we hide the switcher if user clicked on the foreground
-     * user (user we're already logged in as).
-     */
-    private void onUserSelected(UserGridRecyclerView.UserRecord record) {
-        mSelectedUser = record;
-        if (record.mInfo != null) {
-            if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
-                mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
-                return;
-            }
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
-            }
-        }
-        dismissUserSwitcher();
-    }
-
-    private void dismissUserSwitcher() {
-        if (mSelectedUser == null) {
-            Log.e(TAG, "Request to dismiss user switcher, but no user selected");
-            return;
-        }
-        if (mSelectedUser.mType == UserRecord.FOREGROUND_USER) {
-            hide();
-            mCarStatusBar.dismissKeyguard();
-            return;
-        }
-        // Switching is about to happen, since it takes time, fade out the switcher gradually.
-        fadeOut();
-    }
-
-    private void fadeOut() {
-        mUserGridView.animate()
-                .alpha(0.0f)
-                .setDuration(mShortAnimDuration)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        hide();
-                        mUserGridView.setAlpha(1.0f);
-                    }
-                });
-
-    }
-
-    private boolean hasScreenLock(int uid) {
-        LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
-        return lockPatternUtils.getCredentialTypeForUser(uid)
-                != LockPatternUtils.CREDENTIAL_TYPE_NONE;
-    }
-
-    private boolean hasTrustedDevice(int uid) {
-        if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
-            return false;
-        }
-        return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
-    }
-
-    private OnHideListener mOnHideListener = new OnHideListener() {
-        @Override
-        public void onHide(boolean dismissUserSwitcher) {
-            if (dismissUserSwitcher) {
-                dismissUserSwitcher();
-            } else {
-                // Re-draw the parent view, otherwise the unlock dialog will not be removed from
-                // the screen immediately.
-                mParent.invalidate();
-            }
-
-        }
-    };
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java
new file mode 100644
index 0000000..6e0db4f
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+
+/**
+ * Owns a {@link View} that is present in SystemUIOverlayWindow.
+ */
+public class OverlayViewController {
+    private final int mStubId;
+    private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+    private View mLayout;
+
+    public OverlayViewController(int stubId,
+            OverlayViewGlobalStateController overlayViewGlobalStateController) {
+        mLayout = null;
+        mStubId = stubId;
+        mOverlayViewGlobalStateController = overlayViewGlobalStateController;
+    }
+
+    /**
+     * Shows content of {@link OverlayViewController}.
+     *
+     * Should be used to show view externally and in particular by {@link OverlayViewMediator}.
+     */
+    public final void start() {
+        mOverlayViewGlobalStateController.showView(/* viewController= */ this, this::show);
+    }
+
+    /**
+     * Hides content of {@link OverlayViewController}.
+     *
+     * Should be used to hide view externally and in particular by {@link OverlayViewMediator}.
+     */
+    public final void stop() {
+        mOverlayViewGlobalStateController.hideView(/* viewController= */ this, this::hide);
+    }
+
+
+    /**
+     * Inflate layout owned by controller.
+     */
+    public final void inflate(ViewGroup baseLayout) {
+        ViewStub viewStub = baseLayout.findViewById(mStubId);
+        mLayout = viewStub.inflate();
+        onFinishInflate();
+    }
+
+    /**
+     * Called once inflate finishes.
+     */
+    protected void onFinishInflate() {
+        // no-op
+    }
+
+    /**
+     * Returns [@code true} if layout owned by controller has been inflated.
+     */
+    public final boolean isInflated() {
+        return mLayout != null;
+    }
+
+    private void show() {
+        if (mLayout == null) {
+            // layout must be inflated before show() is called.
+            return;
+        }
+        showInternal();
+    }
+
+    /**
+     * Subclasses should override this method to implement reveal animations and implement logic
+     * specific to when the layout owned by the controller is shown.
+     *
+     * Should only be overridden by Superclass but not called by any {@link OverlayViewMediator}.
+     */
+    protected void showInternal() {
+        mLayout.setVisibility(View.VISIBLE);
+    }
+
+    private void hide() {
+        if (mLayout == null) {
+            // layout must be inflated before hide() is called.
+            return;
+        }
+        hideInternal();
+    }
+
+    /**
+     * Subclasses should override this method to implement conceal animations and implement logic
+     * specific to when the layout owned by the controller is hidden.
+     *
+     * Should only be overridden by Superclass but not called by any {@link OverlayViewMediator}.
+     */
+    protected void hideInternal() {
+        mLayout.setVisibility(View.GONE);
+    }
+
+    /**
+     * Provides access to layout owned by controller.
+     */
+    protected final View getLayout() {
+        return mLayout;
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java
new file mode 100644
index 0000000..2d4a9e6
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * This controller is responsible for the following:
+ * <p><ul>
+ * <li>Holds the global state for SystemUIOverlayWindow.
+ * <li>Allows {@link SystemUIOverlayWindowManager} to register {@link OverlayViewMediator}(s).
+ * <li>Enables {@link OverlayViewController)(s) to reveal/conceal themselves while respecting the
+ * global state of SystemUIOverlayWindow.
+ * </ul>
+ */
+@Singleton
+public class OverlayViewGlobalStateController {
+    private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName();
+    private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
+    private final CarNavigationBarController mCarNavigationBarController;
+    @VisibleForTesting
+    Set<String> mShownSet;
+
+    @Inject
+    public OverlayViewGlobalStateController(
+            CarNavigationBarController carNavigationBarController,
+            SystemUIOverlayWindowController systemUIOverlayWindowController) {
+        mSystemUIOverlayWindowController = systemUIOverlayWindowController;
+        mSystemUIOverlayWindowController.attach();
+        mCarNavigationBarController = carNavigationBarController;
+        mShownSet = new HashSet<>();
+    }
+
+    /**
+     * Register {@link OverlayViewMediator} to use in SystemUIOverlayWindow.
+     */
+    public void registerMediator(OverlayViewMediator overlayViewMediator) {
+        Log.d(TAG, "Registering content mediator: " + overlayViewMediator.getClass().getName());
+
+        overlayViewMediator.registerListeners();
+        overlayViewMediator.setupOverlayContentViewControllers();
+    }
+
+    /**
+     * Show content in Overlay Window.
+     */
+    public void showView(OverlayViewController viewController, Runnable show) {
+        if (mShownSet.isEmpty()) {
+            mCarNavigationBarController.hideBars();
+            mSystemUIOverlayWindowController.setWindowExpanded(true);
+        }
+
+        if (!viewController.isInflated()) {
+            viewController.inflate(mSystemUIOverlayWindowController.getBaseLayout());
+        }
+
+        show.run();
+        mShownSet.add(viewController.getClass().getName());
+
+        Log.d(TAG, "Content shown: " + viewController.getClass().getName());
+    }
+
+    /**
+     * Hide content in Overlay Window.
+     */
+    public void hideView(OverlayViewController viewController, Runnable hide) {
+        if (!viewController.isInflated()) {
+            Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
+                    + viewController.getClass().getName());
+            return;
+        }
+        if (!mShownSet.contains(viewController.getClass().getName())) {
+            Log.d(TAG, "Content cannot be hidden since it isn't shown: "
+                    + viewController.getClass().getName());
+            return;
+        }
+
+        hide.run();
+        mShownSet.remove(viewController.getClass().getName());
+
+        if (mShownSet.isEmpty()) {
+            mCarNavigationBarController.showBars();
+            mSystemUIOverlayWindowController.setWindowExpanded(false);
+        }
+
+        Log.d(TAG, "Content hidden: " + viewController.getClass().getName());
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewMediator.java
new file mode 100644
index 0000000..7c34fb4
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewMediator.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+/**
+ * Controls when to show and hide {@link OverlayViewController}(s).
+ */
+public interface OverlayViewMediator {
+
+    /**
+     * Register listeners that could use ContentVisibilityAdjuster to show/hide content.
+     */
+    void registerListeners();
+
+    /**
+     * Allows for post-inflation callbacks and listeners to be set inside required {@link
+     * OverlayViewController}(s).
+     */
+    void setupOverlayContentViewControllers();
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java
new file mode 100644
index 0000000..b0e3089
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Dagger injection module for {@link SystemUIOverlayWindowManager}
+ */
+@Module
+public abstract class OverlayWindowModule {
+    /** Inject into FullscreenUserSwitcherViewsMediator. */
+    @Binds
+    @IntoMap
+    @ClassKey(FullscreenUserSwitcherViewMediator.class)
+    public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator(
+            FullscreenUserSwitcherViewMediator overlayViewsMediator);
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowController.java
similarity index 95%
rename from packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
rename to packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowController.java
index 3f55ac8..9c456ee 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.car;
+package com.android.systemui.window;
 
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
@@ -41,7 +41,7 @@
  * this window for the notification panel.
  */
 @Singleton
-public class SystemUIPrimaryWindowController implements
+public class SystemUIOverlayWindowController implements
         ConfigurationController.ConfigurationListener {
 
     private final Context mContext;
@@ -57,7 +57,7 @@
     private boolean mIsAttached = false;
 
     @Inject
-    public SystemUIPrimaryWindowController(
+    public SystemUIOverlayWindowController(
             Context context,
             @Main Resources resources,
             WindowManager windowManager,
@@ -77,7 +77,7 @@
 
         mLpChanged = new WindowManager.LayoutParams();
         mBaseLayout = (ViewGroup) LayoutInflater.from(context)
-                .inflate(R.layout.sysui_primary_window, /* root= */ null, false);
+                .inflate(R.layout.sysui_overlay_window, /* root= */ null, false);
 
         configurationController.addCallback(this);
     }
@@ -115,7 +115,7 @@
         mLp.gravity = Gravity.TOP;
         mLp.setFitInsetsTypes(/* types= */ 0);
         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-        mLp.setTitle("SystemUIPrimaryWindow");
+        mLp.setTitle("SystemUIOverlayWindow");
         mLp.packageName = mContext.getPackageName();
         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java
new file mode 100644
index 0000000..af0f17d
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import android.content.Context;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+/**
+ * Registers {@link OverlayViewMediator}(s) and synchronizes their calls to hide/show {@link
+ * OverlayViewController}(s) to allow for the correct visibility of system bars.
+ */
+@Singleton
+public class SystemUIOverlayWindowManager extends SystemUI {
+    private static final String TAG = "SystemUIOverlayWindowManager";
+    private final Map<Class<?>, Provider<OverlayViewMediator>>
+            mContentMediatorCreators;
+    private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+    @Inject
+    public SystemUIOverlayWindowManager(
+            Context context,
+            Map<Class<?>, Provider<OverlayViewMediator>> contentMediatorCreators,
+            OverlayViewGlobalStateController overlayViewGlobalStateController) {
+        super(context);
+        mContentMediatorCreators = contentMediatorCreators;
+        mOverlayViewGlobalStateController = overlayViewGlobalStateController;
+    }
+
+    @Override
+    public void start() {
+        String[] names = mContext.getResources().getStringArray(
+                R.array.config_carSystemUIOverlayViewsMediators);
+        startServices(names);
+    }
+
+    private void startServices(String[] services) {
+        for (String clsName : services) {
+            try {
+                OverlayViewMediator obj = resolveContentMediator(clsName);
+                if (obj == null) {
+                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
+                    obj = (OverlayViewMediator) constructor.newInstance(this);
+                }
+                mOverlayViewGlobalStateController.registerMediator(obj);
+            } catch (ClassNotFoundException
+                    | NoSuchMethodException
+                    | IllegalAccessException
+                    | InstantiationException
+                    | InvocationTargetException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+
+    private OverlayViewMediator resolveContentMediator(String className) {
+        return resolve(className, mContentMediatorCreators);
+    }
+
+    private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
+        try {
+            Class<?> clazz = Class.forName(className);
+            Provider<T> provider = creators.get(clazz);
+            return provider == null ? null : provider.get();
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+}
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml
new file mode 100644
index 0000000..5e5efe7
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml
@@ -0,0 +1,22 @@
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:id="@+id/overlay_view_controller_test">
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml
new file mode 100644
index 0000000..165193e
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml
@@ -0,0 +1,30 @@
+<?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.
+  -->
+
+<!-- Fullscreen views in sysui should be listed here in increasing Z order. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@android:color/transparent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ViewStub android:id="@+id/overlay_view_controller_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/overlay_view_controller_stub"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java
new file mode 100644
index 0000000..3be9626
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.tests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class OverlayViewControllerTest extends SysuiTestCase {
+    private MockOverlayViewController mOverlayViewController;
+    private ViewGroup mBaseLayout;
+
+    @Mock
+    private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+    @Captor
+    private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(/* testClass= */ this);
+
+        mOverlayViewController = new MockOverlayViewController(R.id.overlay_view_controller_stub,
+                mOverlayViewGlobalStateController);
+
+        mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
+                R.layout.overlay_view_controller_test, /* root= */ null);
+    }
+
+    @Test
+    public void inflate_layoutInitialized() {
+        mOverlayViewController.inflate(mBaseLayout);
+
+        assertThat(mOverlayViewController.getLayout().getId()).isEqualTo(
+                R.id.overlay_view_controller_test);
+    }
+
+    @Test
+    public void inflate_onFinishInflateCalled() {
+        mOverlayViewController.inflate(mBaseLayout);
+
+        assertThat(mOverlayViewController.mOnFinishInflateCalled).isTrue();
+    }
+
+    @Test
+    public void start_viewInflated_viewShown() {
+        mOverlayViewController.inflate(mBaseLayout);
+
+        mOverlayViewController.start();
+
+        verify(mOverlayViewGlobalStateController).showView(eq(mOverlayViewController),
+                mRunnableArgumentCaptor.capture());
+
+        mRunnableArgumentCaptor.getValue().run();
+
+        assertThat(mOverlayViewController.mShowInternalCalled).isTrue();
+    }
+
+    @Test
+    public void stop_viewInflated_viewHidden() {
+        mOverlayViewController.inflate(mBaseLayout);
+
+        mOverlayViewController.stop();
+
+        verify(mOverlayViewGlobalStateController).hideView(eq(mOverlayViewController),
+                mRunnableArgumentCaptor.capture());
+
+        mRunnableArgumentCaptor.getValue().run();
+
+        assertThat(mOverlayViewController.mHideInternalCalled).isTrue();
+    }
+
+    @Test
+    public void start_viewNotInflated_viewNotShown() {
+        mOverlayViewController.start();
+
+        verify(mOverlayViewGlobalStateController).showView(eq(mOverlayViewController),
+                mRunnableArgumentCaptor.capture());
+
+        mRunnableArgumentCaptor.getValue().run();
+
+        assertThat(mOverlayViewController.mShowInternalCalled).isFalse();
+    }
+
+    @Test
+    public void stop_viewNotInflated_viewNotHidden() {
+        mOverlayViewController.stop();
+
+        verify(mOverlayViewGlobalStateController).hideView(eq(mOverlayViewController),
+                mRunnableArgumentCaptor.capture());
+
+        mRunnableArgumentCaptor.getValue().run();
+
+        assertThat(mOverlayViewController.mHideInternalCalled).isFalse();
+    }
+
+    private static class MockOverlayViewController extends OverlayViewController {
+        boolean mOnFinishInflateCalled = false;
+        boolean mShowInternalCalled = false;
+        boolean mHideInternalCalled = false;
+
+        MockOverlayViewController(int stubId,
+                OverlayViewGlobalStateController overlayViewGlobalStateController) {
+            super(stubId, overlayViewGlobalStateController);
+        }
+
+        @Override
+        protected void onFinishInflate() {
+            mOnFinishInflateCalled = true;
+        }
+
+        @Override
+        protected void showInternal() {
+            mShowInternalCalled = true;
+        }
+
+        @Override
+        protected void hideInternal() {
+            mHideInternalCalled = true;
+        }
+    }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java
new file mode 100644
index 0000000..03354d1
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
+    private static final String MOCK_OVERLAY_VIEW_CONTROLLER_NAME = "OverlayViewController";
+
+    private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+    private ViewGroup mBaseLayout;
+
+    @Mock
+    private CarNavigationBarController mCarNavigationBarController;
+    @Mock
+    private SystemUIOverlayWindowController mSystemUIOverlayWindowController;
+    @Mock
+    private OverlayViewMediator mOverlayViewMediator;
+    @Mock
+    private OverlayViewController mOverlayViewController;
+    @Mock
+    private Runnable mRunnable;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(/* testClass= */ this);
+
+        mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
+                mCarNavigationBarController, mSystemUIOverlayWindowController);
+
+        verify(mSystemUIOverlayWindowController).attach();
+
+        mBaseLayout = new FrameLayout(mContext);
+
+        when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
+    }
+
+    @Test
+    public void registerMediator_overlayViewMediatorListenersRegistered() {
+        mOverlayViewGlobalStateController.registerMediator(mOverlayViewMediator);
+
+        verify(mOverlayViewMediator).registerListeners();
+    }
+
+    @Test
+    public void registerMediator_overlayViewMediatorViewControllerSetup() {
+        mOverlayViewGlobalStateController.registerMediator(mOverlayViewMediator);
+
+        verify(mOverlayViewMediator).setupOverlayContentViewControllers();
+    }
+
+    @Test
+    public void showView_nothingAlreadyShown_navigationBarsHidden() {
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mCarNavigationBarController).hideBars();
+    }
+
+    @Test
+    public void showView_nothingAlreadyShown_windowIsExpanded() {
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mSystemUIOverlayWindowController).setWindowExpanded(true);
+    }
+
+    @Test
+    public void showView_somethingAlreadyShown_navigationBarsHidden() {
+        mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mCarNavigationBarController, never()).hideBars();
+    }
+
+    @Test
+    public void showView_somethingAlreadyShown_windowIsExpanded() {
+        mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mSystemUIOverlayWindowController, never()).setWindowExpanded(true);
+    }
+
+    @Test
+    public void showView_viewControllerNotInflated_inflateViewController() {
+        when(mOverlayViewController.isInflated()).thenReturn(false);
+
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mOverlayViewController).inflate(mBaseLayout);
+    }
+
+    @Test
+    public void showView_viewControllerInflated_inflateViewControllerNotCalled() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mOverlayViewController, never()).inflate(mBaseLayout);
+    }
+
+    @Test
+    public void showView_showRunnableCalled() {
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void showView_overlayViewControllerAddedToShownSet() {
+        mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+        assertThat(mOverlayViewGlobalStateController.mShownSet.contains(
+                mOverlayViewController.getClass().getName())).isTrue();
+    }
+
+    @Test
+    public void hideView_viewControllerNotInflated_hideRunnableNotCalled() {
+        when(mOverlayViewController.isInflated()).thenReturn(false);
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mRunnable, never()).run();
+    }
+
+    @Test
+    public void hideView_nothingShown_hideRunnableNotCalled() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.clear();
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mRunnable, never()).run();
+    }
+
+    @Test
+    public void hideView_viewControllerNotShown_hideRunnableNotCalled() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mRunnable, never()).run();
+    }
+
+    @Test
+    public void hideView_viewControllerShown_hideRunnableCalled() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(
+                mOverlayViewController.getClass().getName());
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void hideView_viewControllerOnlyShown_nothingShown() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(
+                mOverlayViewController.getClass().getName());
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        assertThat(mOverlayViewGlobalStateController.mShownSet.isEmpty()).isTrue();
+    }
+
+    @Test
+    public void hideView_viewControllerNotOnlyShown_navigationBarNotShown() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(
+                mOverlayViewController.getClass().getName());
+        mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mCarNavigationBarController, never()).showBars();
+    }
+
+    @Test
+    public void hideView_viewControllerNotOnlyShown_windowNotCollapsed() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(
+                mOverlayViewController.getClass().getName());
+        mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mSystemUIOverlayWindowController, never()).setWindowExpanded(false);
+    }
+
+    @Test
+    public void hideView_viewControllerOnlyShown_navigationBarShown() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(
+                mOverlayViewController.getClass().getName());
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mCarNavigationBarController).showBars();
+    }
+
+    @Test
+    public void hideView_viewControllerOnlyShown_windowCollapsed() {
+        when(mOverlayViewController.isInflated()).thenReturn(true);
+        mOverlayViewGlobalStateController.mShownSet.add(
+                mOverlayViewController.getClass().getName());
+
+        mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+        verify(mSystemUIOverlayWindowController).setWindowExpanded(false);
+    }
+}
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
index 26bcd54..bd9dc4ff 100644
--- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
@@ -16,6 +16,8 @@
 
 package com.android.settingslib.schedulesprovider;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -25,25 +27,25 @@
 
 /**
  * Schedule data item containing the schedule title text, the summary text which is displayed on the
- * summary of the Settings preference and an {@link Intent} which Settings will launch when the
- * user clicks on the preference.
+ * summary of the Settings preference and a {@link PendingIntent} which Settings will launch
+ * when the user clicks on the preference.
  */
 public class ScheduleInfo implements Parcelable {
     private static final String TAG = "ScheduleInfo";
     private final String mTitle;
     private final String mSummary;
-    private final Intent mIntent;
+    private final PendingIntent mPendingIntent;
 
     public ScheduleInfo(Builder builder) {
         mTitle = builder.mTitle;
         mSummary = builder.mSummary;
-        mIntent = builder.mIntent;
+        mPendingIntent = builder.mPendingIntent;
     }
 
     private ScheduleInfo(Parcel in) {
         mTitle = in.readString();
         mSummary = in.readString();
-        mIntent = in.readParcelable(Intent.class.getClassLoader());
+        mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
     }
 
     /**
@@ -61,11 +63,11 @@
     }
 
     /**
-     * Returns an {@link Intent} which Settings will launch when the user clicks on a schedule
-     * preference.
+     * Returns a {@link PendingIntent} which Settings will launch when the user clicks on a
+     * schedule preference.
      */
-    public Intent getIntent() {
-        return mIntent;
+    public PendingIntent getPendingIntent() {
+        return mPendingIntent;
     }
 
     /**
@@ -74,14 +76,15 @@
      * @return {@code true} if all member variables are valid.
      */
     public boolean isValid() {
-        return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary) && (mIntent != null);
+        return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary)
+                && (mPendingIntent != null);
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mTitle);
         dest.writeString(mSummary);
-        dest.writeParcelable(mIntent, flags);
+        dest.writeParcelable(mPendingIntent, flags);
     }
 
     @Override
@@ -104,7 +107,7 @@
     @NonNull
     @Override
     public String toString() {
-        return "title: " + mTitle + ", summary: " + mSummary + ", intent: " + mIntent;
+        return "title: " + mTitle + ", summary: " + mSummary + ", pendingIntent: " + mPendingIntent;
     }
 
     /**
@@ -113,7 +116,7 @@
     public static class Builder {
         private String mTitle;
         private String mSummary;
-        private Intent mIntent;
+        private PendingIntent mPendingIntent;
 
         /**
          * Sets the title.
@@ -138,13 +141,15 @@
         }
 
         /**
-         * Sets the {@link Intent}.
+         * Sets the {@link PendingIntent}.
+         * <p>The {@link PendingIntent} should be created with
+         * {@link PendingIntent#getActivity(Context, int, Intent, int)}.
          *
-         * @param intent The action when user clicks the preference.
+         * @param pendingIntent The pending intent to send when the user clicks the preference.
          * @return This instance.
          */
-        public Builder setIntent(@NonNull Intent intent) {
-            mIntent = intent;
+        public Builder setPendingIntent(@NonNull PendingIntent pendingIntent) {
+            mPendingIntent = pendingIntent;
             return this;
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index c9c847f..18eb187 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -218,24 +218,32 @@
     }
 
     public boolean supportsHighQualityAudio(BluetoothDevice device) {
-        int support = mService.supportsOptionalCodecs(device);
+        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        if (bluetoothDevice == null) {
+            return false;
+        }
+        int support = mService.isOptionalCodecsSupported(bluetoothDevice);
         return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED;
     }
 
     public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
-        int enabled = mService.getOptionalCodecsEnabled(device);
+        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        if (bluetoothDevice == null) {
+            return false;
+        }
+        int enabled = mService.isOptionalCodecsEnabled(bluetoothDevice);
         if (enabled != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN) {
             return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED;
-        } else if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED &&
-                supportsHighQualityAudio(device)) {
+        } else if (getConnectionStatus(bluetoothDevice) != BluetoothProfile.STATE_CONNECTED
+                && supportsHighQualityAudio(bluetoothDevice)) {
             // Since we don't have a stored preference and the device isn't connected, just return
             // true since the default behavior when the device gets connected in the future would be
             // to have optional codecs enabled.
             return true;
         }
         BluetoothCodecConfig codecConfig = null;
-        if (mService.getCodecStatus(device) != null) {
-            codecConfig = mService.getCodecStatus(device).getCodecConfig();
+        if (mService.getCodecStatus(bluetoothDevice) != null) {
+            codecConfig = mService.getCodecStatus(bluetoothDevice).getCodecConfig();
         }
         if (codecConfig != null)  {
             return !codecConfig.isMandatoryCodec();
@@ -245,23 +253,28 @@
     }
 
     public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
+        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+        if (bluetoothDevice == null) {
+            return;
+        }
         int prefValue = enabled
                 ? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED
                 : BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
-        mService.setOptionalCodecsEnabled(device, prefValue);
-        if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
+        mService.setOptionalCodecsEnabled(bluetoothDevice, prefValue);
+        if (getConnectionStatus(bluetoothDevice) != BluetoothProfile.STATE_CONNECTED) {
             return;
         }
         if (enabled) {
-            mService.enableOptionalCodecs(device);
+            mService.enableOptionalCodecs(bluetoothDevice);
         } else {
-            mService.disableOptionalCodecs(device);
+            mService.disableOptionalCodecs(bluetoothDevice);
         }
     }
 
     public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
+        BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
         int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
-        if (!supportsHighQualityAudio(device)
+        if (bluetoothDevice == null || !supportsHighQualityAudio(device)
                 || getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
             return mContext.getString(unknownCodecId);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3ae9e1e..7e78a78 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -311,6 +311,21 @@
         return -1;
     }
 
+    CharSequence getSessionName() {
+        if (TextUtils.isEmpty(mPackageName)) {
+            Log.w(TAG, "Unable to get session name. The package name is null or empty!");
+            return null;
+        }
+
+        final RoutingSessionInfo info = getRoutingSessionInfo();
+        if (info != null) {
+            return info.getName();
+        }
+
+        Log.w(TAG, "Unable to get session name for package: " + mPackageName);
+        return null;
+    }
+
     private void refreshDevices() {
         mMediaDevices.clear();
         mCurrentConnectedDevice = null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index c70811f..adb3c11 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -324,6 +324,15 @@
         return mInfoMediaManager.getSessionVolume();
     }
 
+    /**
+     * Gets the user-visible name of the {@link android.media.RoutingSessionInfo}.
+     *
+     * @return current name of the session, and return {@code null} if not found.
+     */
+    public CharSequence getSessionName() {
+        return mInfoMediaManager.getSessionName();
+    }
+
     private MediaDevice updateCurrentConnectedDevice() {
         MediaDevice phoneMediaDevice = null;
         for (MediaDevice device : mMediaDevices) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index 414c39b..9afdd43c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -69,30 +69,31 @@
         mProfile = new A2dpProfile(mContext, mDeviceManager, mProfileManager);
         mServiceListener = mShadowBluetoothAdapter.getServiceListener();
         mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp);
+        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mDevice);
     }
 
     @Test
     public void supportsHighQualityAudio() {
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
         assertThat(mProfile.supportsHighQualityAudio(mDevice)).isTrue();
 
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
         assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse();
 
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN);
         assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse();
     }
 
     @Test
     public void isHighQualityAudioEnabled() {
-        when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsEnabled(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
         assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
 
-        when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsEnabled(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
         assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
 
@@ -100,16 +101,16 @@
         // then isHighQualityAudioEnabled() should return true or false based on whether optional
         // codecs are supported. If the device is connected then we should ask it directly, but if
         // the device isn't connected then rely on the stored pref about such support.
-        when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsEnabled(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN);
         when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
                 BluetoothProfile.STATE_DISCONNECTED);
 
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
         assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
 
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
         assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
 
@@ -151,14 +152,14 @@
 
         // Most tests want to simulate optional codecs being supported by the device, so do that
         // by default here.
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(any())).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
     }
 
     @Test
     public void getLableCodecsNotSupported() {
         setupLabelTest();
-        when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+        when(mBluetoothA2dp.isOptionalCodecsSupported(any())).thenReturn(
                 BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
         assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(UNKNOWN_CODEC_LABEL);
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index edb121b..7cd0a7c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -460,4 +460,37 @@
 
         assertThat(mInfoMediaManager.releaseSession()).isTrue();
     }
+
+    @Test
+    public void getSessionName_packageNameIsNull_returnNull() {
+        mInfoMediaManager.mPackageName = null;
+
+        assertThat(mInfoMediaManager.getSessionName()).isNull();
+    }
+
+    @Test
+    public void getSessionName_notContainPackageName_returnNull() {
+        final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+        final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+        routingSessionInfos.add(info);
+
+        mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+        when(info.getClientPackageName()).thenReturn("com.fake.packagename");
+        when(info.getName()).thenReturn(TEST_NAME);
+
+        assertThat(mInfoMediaManager.getSessionName()).isNull();
+    }
+
+    @Test
+    public void getSessionName_containPackageName_returnName() {
+        final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+        final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+        routingSessionInfos.add(info);
+
+        mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+        when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(info.getName()).thenReturn(TEST_NAME);
+
+        assertThat(mInfoMediaManager.getSessionName()).isEqualTo(TEST_NAME);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
index 5ec89ed..b4b910d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
@@ -17,11 +17,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
 
 @RunWith(RobolectricTestRunner.class)
 public class ScheduleInfoTest {
@@ -29,10 +32,12 @@
     private static final String TEST_SUMMARY = "Night Light summary";
     private static final String TEST_EMPTY_SUMMARY = "";
 
+    private final Context mContext = RuntimeEnvironment.application;
+
     @Test
     public void builder_usedValidArguments_isValid() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
         assertThat(info).isNotNull();
         assertThat(info.isValid()).isTrue();
@@ -40,15 +45,16 @@
 
     @Test
     public void builder_useEmptySummary_isInvalid() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY,
+                pendingIntent);
 
         assertThat(info).isNotNull();
         assertThat(info.isValid()).isFalse();
     }
 
     @Test
-    public void builder_intentIsNull_isInvalid() {
+    public void builder_pendingIntentIsNull_isInvalid() {
         final ScheduleInfo info = new ScheduleInfo.Builder()
                 .setTitle(TEST_TITLE)
                 .setSummary(TEST_SUMMARY)
@@ -60,39 +66,40 @@
 
     @Test
     public void getTitle_setValidTitle_shouldReturnSameCorrectTitle() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
         assertThat(info.getTitle()).isEqualTo(TEST_TITLE);
     }
 
     @Test
     public void getSummary_setValidSummary_shouldReturnSameCorrectSummary() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
         assertThat(info.getSummary()).isEqualTo(TEST_SUMMARY);
     }
 
     @Test
-    public void getIntent_setValidIntent_shouldReturnSameCorrectIntent() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+    public void getPendingIntent_setValidPendingIntent_shouldReturnSameCorrectIntent() {
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
-        assertThat(info.getIntent()).isEqualTo(intent);
+        assertThat(info.getPendingIntent()).isEqualTo(pendingIntent);
     }
 
-    private static Intent createTestIntent() {
-        return new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+    private static PendingIntent createTestPendingIntent(Context context) {
+        final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
                 Intent.CATEGORY_DEFAULT);
+        return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
     }
 
     private static ScheduleInfo createTestScheduleInfo(String title, String summary,
-            Intent intent) {
+            PendingIntent pendingIntent) {
         return new ScheduleInfo.Builder()
                 .setTitle(title)
                 .setSummary(summary)
-                .setIntent(intent)
+                .setPendingIntent(pendingIntent)
                 .build();
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
index eb2e8e0..6b92082 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
@@ -19,6 +19,8 @@
 
 import static org.robolectric.Shadows.shadowOf;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 
@@ -27,6 +29,7 @@
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
 
@@ -35,13 +38,16 @@
     private static final String INVALID_PACKAGE = "com.android.sunny";
     private static final String VALID_PACKAGE = "com.android.settings";
     private static final String INVALID_METHOD = "queryTestData";
+
+    private final Context mContext = RuntimeEnvironment.application;
+
     private TestSchedulesProvider mProvider;
 
     @Before
     public void setUp() {
         mProvider = Robolectric.setupContentProvider(TestSchedulesProvider.class);
         shadowOf(mProvider).setCallingPackage(VALID_PACKAGE);
-        mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo());
+        mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo(mContext));
     }
 
     @Test
@@ -76,7 +82,7 @@
 
     @Test
     public void call_addTwoValidData_returnScheduleInfoData() {
-        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos());
+        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos(mContext));
         final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
                 null /* arg */, null /* extras */);
 
@@ -89,7 +95,8 @@
 
     @Test
     public void call_addTwoValidDataAndOneInvalidData_returnTwoScheduleInfoData() {
-        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo());
+        mProvider.setScheduleInfos(
+                TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo(mContext));
         final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
                 null /* arg */, null /* extras */);
 
@@ -112,55 +119,56 @@
             mScheduleInfos = scheduleInfos;
         }
 
-        private static ArrayList<ScheduleInfo> createOneValidScheduleInfo() {
+        private static ArrayList<ScheduleInfo> createOneValidScheduleInfo(Context context) {
             final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
-            final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            final ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
-                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+
+            final ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+                    "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+                    "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
             return scheduleInfos;
         }
 
-        private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos() {
+        private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos(Context context) {
             final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
-            Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
-                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+                    "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+                    "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
-            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
             info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
-                    "Display summary").setIntent(intent).build();
+                    "Display summary").setPendingIntent(
+                    createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
             return scheduleInfos;
         }
 
-        private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo() {
+        private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo(
+                Context context) {
             final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
-            Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
-                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+                    "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+                    "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
-            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
             info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
-                    "Display summary").setIntent(intent).build();
+                    "Display summary").setPendingIntent(
+                    createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
-            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            info = new ScheduleInfo.Builder().setTitle("").setSummary("Display summary").setIntent(
-                    intent).build();
+            info = new ScheduleInfo.Builder().setTitle("").setSummary(
+                    "Display summary").setPendingIntent(
+                    createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
             return scheduleInfos;
         }
+
+        private static PendingIntent createTestPendingIntent(Context context, String action) {
+            final Intent intent = new Intent(action).addCategory(Intent.CATEGORY_DEFAULT);
+            return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
+        }
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 2431381..8fa98c8 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -162,5 +162,6 @@
         Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT,
         Settings.Secure.PEOPLE_STRIP,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
+        Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 5553469..75c5f95 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -245,5 +245,8 @@
                 new InclusiveIntegerRangeValidator(
                         Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
                         Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
+                ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d677687..8789a5c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1811,6 +1811,9 @@
         dumpSetting(s, p,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
                 SecureSettingsProto.Accessibility.ACCESSIBILITY_MAGNIFICATION_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
+                SecureSettingsProto.Accessibility.BUTTON_LONG_PRESS_TARGETS);
         p.end(accessibilityToken);
 
         final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 617ed4e..30b461d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -180,6 +180,8 @@
 
     <!-- Adding Controls to SystemUI -->
     <uses-permission android:name="android.permission.BIND_CONTROLS" />
+    <!-- Check foreground controls applications -->
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <!-- Quick Settings tile: Night Mode / Dark Theme -->
     <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
@@ -686,6 +688,25 @@
                   android:visibleToInstantApps="true">
         </activity>
 
+        <receiver android:name=".controls.management.ControlsRequestReceiver">
+            <intent-filter>
+                <action android:name="android.service.controls.action.ADD_CONTROL" />
+            </intent-filter>
+        </receiver>
+
+        <!-- started from ControlsFavoritingActivity -->
+        <activity
+            android:name=".controls.management.ControlsRequestDialog"
+            android:exported="true"
+            android:theme="@style/Theme.ControlsRequestDialog"
+            android:finishOnCloseSystemDialogs="true"
+            android:showForAllUsers="true"
+            android:clearTaskOnLaunch="true"
+            android:launchMode="singleTask"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+            android:excludeFromRecents="true"
+            android:visibleToInstantApps="true"/>
+
         <!-- Doze with notifications, run in main sysui process for every user  -->
         <service
             android:name=".doze.DozeService"
diff --git a/packages/SystemUI/res/layout/controls_dialog.xml b/packages/SystemUI/res/layout/controls_dialog.xml
new file mode 100644
index 0000000..3effaf5
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_dialog.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.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="@dimen/controls_dialog_padding"
+    android:layout_margin="@dimen/controls_dialog_padding"
+    >
+
+    <include
+        android:id="@+id/control"
+        layout="@layout/controls_base_item"
+        android:layout_width="@dimen/controls_dialog_control_width"
+        android:layout_height="@dimen/control_height"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/controls_dialog_padding"
+        android:layout_marginBottom="@dimen/controls_dialog_padding"
+    />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 8460612..6a7f9e2 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -121,7 +121,6 @@
                 android:layout_marginEnd="2dp"
                 android:ellipsize="end"
                 android:text="@string/notification_delegate_header"
-                android:layout_toEndOf="@id/pkg_divider"
                 android:maxLines="1" />
 
         </LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 5d03eee..6ab573b 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -27,51 +27,81 @@
     android:paddingStart="@*android:dimen/notification_content_margin_start">
 
     <!-- Package Info -->
-    <RelativeLayout
+    <LinearLayout
         android:id="@+id/header"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="@dimen/notification_guts_conversation_header_height"
+        android:gravity="center_vertical"
         android:clipChildren="false"
         android:clipToPadding="false">
         <ImageView
-            android:id="@+id/pkgicon"
-            android:layout_width="@dimen/notification_guts_header_height"
-            android:layout_height="@dimen/notification_guts_header_height"
+            android:id="@+id/pkg_icon"
+            android:layout_width="@dimen/notification_guts_conversation_icon_size"
+            android:layout_height="@dimen/notification_guts_conversation_icon_size"
             android:layout_centerVertical="true"
             android:layout_alignParentStart="true"
-            android:layout_marginEnd="3dp" />
-        <TextView
-            android:id="@+id/pkgname"
-            android:layout_width="wrap_content"
+            android:layout_marginEnd="15dp" />
+        <LinearLayout
+            android:id="@+id/names"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:orientation="vertical"
+
             android:layout_height="wrap_content"
+            android:minHeight="@dimen/notification_guts_conversation_icon_size"
             android:layout_centerVertical="true"
-            style="@style/TextAppearance.NotificationImportanceHeader"
-            android:layout_marginStart="3dp"
-            android:layout_marginEnd="2dp"
-            android:layout_toEndOf="@id/pkgicon"
-            android:singleLine="true" />
-        <TextView
-            android:id="@+id/pkg_divider"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            style="@style/TextAppearance.NotificationImportanceHeader"
-            android:layout_marginStart="2dp"
-            android:layout_marginEnd="2dp"
-            android:layout_toEndOf="@id/pkgname"
-            android:text="@*android:string/notification_header_divider_symbol" />
-        <TextView
-            android:id="@+id/delegate_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            style="@style/TextAppearance.NotificationImportanceHeader"
-            android:layout_marginStart="2dp"
-            android:layout_marginEnd="2dp"
-            android:ellipsize="end"
-            android:text="@string/notification_delegate_header"
-            android:layout_toEndOf="@id/pkg_divider"
-            android:maxLines="1" />
+            android:gravity="center_vertical"
+            android:layout_alignEnd="@id/pkg_icon"
+            android:layout_toEndOf="@id/pkg_icon"
+            android:layout_alignStart="@id/mute">
+            <TextView
+                android:id="@+id/channel_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.NotificationImportanceChannel"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="start"
+                android:orientation="horizontal">
+                <TextView
+                    android:id="@+id/pkg_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/TextAppearance.NotificationImportanceChannelGroup"
+                    android:ellipsize="end"
+                    android:maxLines="1"/>
+                <TextView
+                    android:id="@+id/group_divider"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    style="@style/TextAppearance.NotificationImportanceHeader"
+                    android:layout_marginStart="2dp"
+                    android:layout_marginEnd="2dp"
+                    android:text="@*android:string/notification_header_divider_symbol" />
+                <TextView
+                    android:id="@+id/group_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    style="@style/TextAppearance.NotificationImportanceChannel"/>
+            </LinearLayout>
+            <TextView
+                android:id="@+id/delegate_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                style="@style/TextAppearance.NotificationImportanceHeader"
+                android:layout_marginStart="2dp"
+                android:layout_marginEnd="2dp"
+                android:ellipsize="end"
+                android:text="@string/notification_delegate_header"
+                android:maxLines="1" />
+
+        </LinearLayout>
+
+        <!-- end aligned fields -->
         <!-- Optional link to app. Only appears if the channel is not disabled and the app
 asked for it -->
         <ImageButton
@@ -95,91 +125,6 @@
             android:src="@drawable/ic_settings"
             android:layout_alignParentEnd="true"
             android:tint="@color/notification_guts_link_icon_tint"/>
-    </RelativeLayout>
-
-    <!-- Channel Info Block -->
-    <LinearLayout
-        android:id="@+id/channel_info"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingEnd="@*android:dimen/notification_content_margin_end"
-        android:gravity="center"
-        android:orientation="vertical">
-        <!-- Channel Name -->
-        <TextView
-            android:id="@+id/channel_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            style="@style/TextAppearance.NotificationImportanceChannel"/>
-        <TextView
-            android:id="@+id/group_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="@style/TextAppearance.NotificationImportanceChannelGroup"
-            android:ellipsize="end"
-            android:maxLines="1"/>
-    </LinearLayout>
-
-    <LinearLayout
-        android:id="@+id/blocking_helper"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/notification_guts_button_spacing"
-        android:layout_marginBottom="@dimen/notification_guts_button_spacing"
-        android:paddingEnd="@*android:dimen/notification_content_margin_end"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:orientation="vertical">
-        <!-- blocking helper text. no need for non-configurable check b/c controls won't be
-        activated in that case -->
-        <TextView
-            android:id="@+id/blocking_helper_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="2dp"
-            android:text="@string/inline_blocking_helper"
-            style="@*android:style/TextAppearance.DeviceDefault.Notification" />
-        <RelativeLayout
-            android:id="@+id/block_buttons"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/notification_guts_button_spacing">
-            <TextView
-                android:id="@+id/blocking_helper_turn_off_notifications"
-                android:text="@string/inline_turn_off_notifications"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_alignParentStart="true"
-                android:width="110dp"
-                android:paddingEnd="15dp"
-                android:breakStrategy="simple"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-            <TextView
-                android:id="@+id/deliver_silently"
-                android:text="@string/inline_deliver_silently_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
-                android:paddingEnd="15dp"
-                android:width="110dp"
-                android:breakStrategy="simple"
-                android:layout_toStartOf="@+id/keep_showing"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-            <TextView
-                android:id="@+id/keep_showing"
-                android:text="@string/inline_keep_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
-                android:width="110dp"
-                android:breakStrategy="simple"
-                android:layout_alignParentEnd="true"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-        </RelativeLayout>
 
     </LinearLayout>
 
@@ -357,34 +302,4 @@
         </RelativeLayout>
 
     </LinearLayout>
-
-    <com.android.systemui.statusbar.notification.row.NotificationUndoLayout
-        android:id="@+id/confirmation"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        android:orientation="horizontal" >
-        <TextView
-            android:id="@+id/confirmation_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start|center_vertical"
-            android:layout_marginStart="@*android:dimen/notification_content_margin_start"
-            android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
-            android:text="@string/notification_channel_disabled"
-            style="@style/TextAppearance.NotificationInfo.Confirmation"/>
-        <TextView
-            android:id="@+id/undo"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:minWidth="@dimen/notification_importance_toggle_size"
-            android:minHeight="@dimen/notification_importance_toggle_size"
-            android:layout_marginTop="@dimen/notification_guts_button_spacing"
-            android:layout_marginBottom="@dimen/notification_guts_button_spacing"
-            android:layout_marginStart="@dimen/notification_guts_button_side_margin"
-            android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
-            android:layout_gravity="end|center_vertical"
-            android:text="@string/inline_undo"
-            style="@style/TextAppearance.NotificationInfo.Button"/>
-    </com.android.systemui.statusbar.notification.row.NotificationUndoLayout>
 </com.android.systemui.statusbar.notification.row.NotificationInfo>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2dc0f5f..7aaf6f9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1249,6 +1249,10 @@
     <dimen name="controls_app_divider_side_margin">32dp</dimen>
 
     <dimen name="controls_card_margin">2dp</dimen>
+    <item name="control_card_elevation" type="dimen" format="float">15</item>
+
+    <dimen name="controls_dialog_padding">8dp</dimen>
+    <dimen name="controls_dialog_control_width">200dp</dimen>
 
     <!-- Screen Record -->
     <dimen name="screenrecord_dialog_padding">18dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bcf3a26..5b28479 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2639,4 +2639,11 @@
     <string name="controls_favorite_load_error">The list of all controls could not be loaded.</string>
     <!-- Controls management controls screen header for Other zone [CHAR LIMIT=60] -->
     <string name="controls_favorite_other_zone_header">Other</string>
+
+    <!-- Controls dialog title [CHAR LIMIT=30] -->
+    <string name="controls_dialog_title">Add to Quick Controls</string>
+    <!-- Controls dialog add to favorites [CHAR LIMIT=30] -->
+    <string name="controls_dialog_ok">Add to favorites</string>
+    <!-- Controls dialog message [CHAR LIMIT=NONE] -->
+    <string name="controls_dialog_message"><xliff:g id="app" example="System UI">%s</xliff:g> suggested this control to add to your favorites.</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2eccf58..125dd8f 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -697,4 +697,7 @@
         <!-- used to override dark/light theming -->
         <item name="*android:colorPopupBackground">@color/control_list_popup_background</item>
     </style>
+
+    <style name="Theme.ControlsRequestDialog" parent="@style/Theme.SystemUI.MediaProjectionAlertDialog"/>
+
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index e554dcd..ebed1fc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -64,7 +64,7 @@
     private final class InputEventReceiver extends BatchedInputEventReceiver {
 
         public InputEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper, Choreographer.getSfInstance());
+            super(inputChannel, looper, Choreographer.getInstance());
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6a6255f..4508fc7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -23,7 +23,6 @@
 import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -455,7 +454,7 @@
      */
     public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
-        if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
+        if (subscriptions.size() == 2) {
             SubscriptionInfo info1 = subscriptions.get(0);
             SubscriptionInfo info2 = subscriptions.get(1);
             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 1324524..86aa640 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -28,6 +28,9 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.Dimension;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -714,6 +717,8 @@
     public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener,
             RegionInterceptableView {
 
+        private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f;
+
         private final DisplayInfo mInfo = new DisplayInfo();
         private final Paint mPaint = new Paint();
         private final List<Rect> mBounds = new ArrayList();
@@ -732,6 +737,8 @@
         private int mRotation;
         private int mInitialPosition;
         private int mPosition;
+        private float mCameraProtectionProgress = HIDDEN_CAMERA_PROTECTION_SCALE;
+        private ValueAnimator mCameraProtectionAnimator;
 
         public DisplayCutoutView(Context context, @BoundsPosition int pos,
                 ScreenDecorations decorations) {
@@ -770,17 +777,18 @@
             getLocationOnScreen(mLocation);
             canvas.translate(-mLocation[0], -mLocation[1]);
 
-            if (mShowProtection && !mProtectionRect.isEmpty()) {
-                mPaint.setColor(mColor);
-                mPaint.setStyle(Paint.Style.FILL);
-                mPaint.setAntiAlias(true);
-                canvas.drawPath(mProtectionPath, mPaint);
-            } else if (!mBoundingPath.isEmpty()) {
+            if (!mBoundingPath.isEmpty()) {
                 mPaint.setColor(mColor);
                 mPaint.setStyle(Paint.Style.FILL);
                 mPaint.setAntiAlias(true);
                 canvas.drawPath(mBoundingPath, mPaint);
             }
+            if (mCameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE
+                    && !mProtectionRect.isEmpty()) {
+                canvas.scale(mCameraProtectionProgress, mCameraProtectionProgress,
+                        mProtectionRect.centerX(), mProtectionRect.centerY());
+                canvas.drawPath(mProtectionPath, mPaint);
+            }
         }
 
         @Override
@@ -815,8 +823,31 @@
 
             mShowProtection = shouldShow;
             updateBoundingPath();
-            requestLayout();
-            invalidate();
+            // Delay the relayout until the end of the animation when hiding the cutout,
+            // otherwise we'd clip it.
+            if (mShowProtection) {
+                requestLayout();
+            }
+            if (mCameraProtectionAnimator != null) {
+                mCameraProtectionAnimator.cancel();
+            }
+            mCameraProtectionAnimator = ValueAnimator.ofFloat(mCameraProtectionProgress,
+                    mShowProtection ? 1.0f : HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750);
+            mCameraProtectionAnimator.setInterpolator(Interpolators.DECELERATE_QUINT);
+            mCameraProtectionAnimator.addUpdateListener(animation -> {
+                mCameraProtectionProgress = (float) animation.getAnimatedValue();
+                invalidate();
+            });
+            mCameraProtectionAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mCameraProtectionAnimator = null;
+                    if (!mShowProtection) {
+                        requestLayout();
+                    }
+                }
+            });
+            mCameraProtectionAnimator.start();
         }
 
         private void update() {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 256c5d5..5077e18 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -81,11 +81,6 @@
         void onGestureCompletion(float velocity);
 
         /**
-         * Called with the Bundle from VoiceInteractionSessionListener.onSetUiHints.
-         */
-        void processBundle(Bundle hints);
-
-        /**
          * Hides any SysUI for the assistant, but _does not_ close the assistant itself.
          */
         void hide();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index f201a6f..68242f0 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -26,7 +26,6 @@
 import android.graphics.PixelFormat;
 import android.metrics.LogMaker;
 import android.os.Build;
-import android.os.Bundle;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -94,11 +93,6 @@
     }
 
     @Override // AssistManager.UiController
-    public void processBundle(Bundle bundle) {
-        Log.e(TAG, "Bundle received but handling is not implemented; ignoring");
-    }
-
-    @Override // AssistManager.UiController
     public void onInvocationProgress(int type, float progress) {
         boolean invocationWasInProgress = mInvocationInProgress;
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 2873811..b33eeba5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -73,6 +73,9 @@
 
     private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
 
+    private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
+    private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false;
+
     /**
      * When true, if a notification has the information necessary to bubble (i.e. valid
      * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
@@ -87,6 +90,15 @@
     }
 
     /**
+     * When true, show a menu with dismissed and aged-out bubbles.
+     */
+    static boolean allowBubbleOverflow(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ALLOW_BUBBLE_OVERFLOW,
+                ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0;
+    }
+
+    /**
      * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
      * are using {@link Notification.MessagingStyle} and have remote input.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 6647069..0cf6d89 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -589,6 +589,9 @@
     }
 
     private void setUpOverflow() {
+        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+            return;
+        }
         int overflowBtnIndex = 0;
         if (mBubbleOverflow == null) {
             mBubbleOverflow = new BubbleOverflow(getContext());
@@ -800,7 +803,8 @@
     @Nullable
     Bubble getExpandedBubble() {
         if (mExpandedBubble == null
-                || (mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
+                || (BubbleExperimentConfig.allowBubbleOverflow(mContext)
+                    && mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
                     && BubbleOverflow.KEY.equals(mExpandedBubble.getKey()))) {
             return null;
         }
@@ -857,6 +861,9 @@
     }
 
     private void updateOverflowBtnVisibility(boolean apply) {
+        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+            return;
+        }
         if (mIsExpanded) {
             if (DEBUG_BUBBLE_STACK_VIEW) {
                 Log.d(TAG, "Show overflow button.");
@@ -1083,7 +1090,8 @@
         float y = event.getRawY();
         if (mIsExpanded) {
             if (isIntersecting(mBubbleContainer, x, y)) {
-                if (isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
+                if (BubbleExperimentConfig.allowBubbleOverflow(mContext)
+                        && isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
                     return mBubbleOverflow.getBtn();
                 }
                 // Could be tapping or dragging a bubble while expanded
@@ -1820,8 +1828,11 @@
      * @return the number of bubbles in the stack view.
      */
     public int getBubbleCount() {
-        // Subtract 1 for the overflow button that is always in the bubble container.
-        return mBubbleContainer.getChildCount() - 1;
+        if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+            // Subtract 1 for the overflow button that is always in the bubble container.
+            return mBubbleContainer.getChildCount() - 1;
+        }
+        return mBubbleContainer.getChildCount();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index f2881d4..7eafe2e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -124,6 +124,18 @@
     fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo>
 
     /**
+     * Adds a single favorite to a given component and structure
+     * @param componentName the name of the service that provides the [Control]
+     * @param structureName the name of the structure that holds the [Control]
+     * @param controlInfo persistent information about the [Control] to be added.
+     */
+    fun addFavorite(
+        componentName: ComponentName,
+        structureName: CharSequence,
+        controlInfo: ControlInfo
+    )
+
+    /**
      * Replaces the favorites for the given structure.
      *
      * Calling this method will eliminate the previous selection of favorites and replace it with a
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index dedd341..f818d19 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -300,6 +300,19 @@
         bindingController.unsubscribe()
     }
 
+    override fun addFavorite(
+        componentName: ComponentName,
+        structureName: CharSequence,
+        controlInfo: ControlInfo
+    ) {
+        if (!confirmAvailability()) return
+        executor.execute {
+            if (Favorites.addFavorite(componentName, structureName, controlInfo)) {
+                persistenceWrapper.storeFavorites(Favorites.getAllStructures())
+            }
+        }
+    }
+
     override fun replaceFavoritesForStructure(structureInfo: StructureInfo) {
         if (!confirmAvailability()) return
         executor.execute {
@@ -437,6 +450,24 @@
         favMap = newFavMap
     }
 
+    fun addFavorite(
+        componentName: ComponentName,
+        structureName: CharSequence,
+        controlInfo: ControlInfo
+    ): Boolean {
+        // Check if control is in favorites
+        if (getControlsForComponent(componentName)
+                        .any { it.controlId == controlInfo.controlId }) {
+            return false
+        }
+        val structureInfo = favMap.get(componentName)
+                ?.firstOrNull { it.structure == structureName }
+                ?: StructureInfo(componentName, structureName, emptyList())
+        val newStructureInfo = structureInfo.copy(controls = structureInfo.controls + controlInfo)
+        replaceControls(newStructureInfo)
+        return true
+    }
+
     fun replaceControls(updatedStructure: StructureInfo) {
         val newFavMap = favMap.toMutableMap()
         val structures = mutableListOf<StructureInfo>()
@@ -456,8 +487,8 @@
             structures.add(updatedStructure)
         }
 
-        newFavMap.put(componentName, structures.toList())
-        favMap = newFavMap.toMap()
+        newFavMap.put(componentName, structures)
+        favMap = newFavMap
     }
 
     fun clear() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
index 859311e..946a236 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.controls.management.ControlsListingController
 import com.android.systemui.controls.management.ControlsListingControllerImpl
 import com.android.systemui.controls.management.ControlsProviderSelectorActivity
+import com.android.systemui.controls.management.ControlsRequestDialog
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.controls.ui.ControlsUiControllerImpl
 import dagger.Binds
@@ -69,4 +70,11 @@
     abstract fun provideControlsFavoritingActivity(
         activity: ControlsFavoritingActivity
     ): Activity
+
+    @Binds
+    @IntoMap
+    @ClassKey(ControlsRequestDialog::class)
+    abstract fun provideControlsRequestDialog(
+        activity: ControlsRequestDialog
+    ): Activity
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index e87cf74..c21f724 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -42,7 +42,8 @@
  * @param onlyFavorites set to true to only display favorites instead of all controls
  */
 class ControlAdapter(
-    private val layoutInflater: LayoutInflater
+    private val layoutInflater: LayoutInflater,
+    private val elevation: Float
 ) : RecyclerView.Adapter<Holder>() {
 
     companion object {
@@ -66,7 +67,7 @@
                         layoutParams.apply {
                             width = ViewGroup.LayoutParams.MATCH_PARENT
                         }
-                        elevation = 15f
+                        elevation = this@ControlAdapter.elevation
                     }
                 ) { id, favorite ->
                     model?.changeFavoriteStatus(id, favorite)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 08a1a50..471f9d3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -142,8 +142,9 @@
         val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
         val itemDecorator = MarginItemDecorator(margin, margin)
         val layoutInflater = LayoutInflater.from(applicationContext)
+        val elevation = resources.getFloat(R.dimen.control_card_elevation)
 
-        adapterAll = ControlAdapter(layoutInflater)
+        adapterAll = ControlAdapter(layoutInflater, elevation)
         recyclerViewAll = requireViewById<RecyclerView>(R.id.listAll).apply {
             adapter = adapterAll
             layoutManager = GridLayoutManager(applicationContext, 2).apply {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
new file mode 100644
index 0000000..463632b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.ComponentName
+import android.content.DialogInterface
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.os.UserHandle
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.ui.RenderInfo
+import com.android.systemui.settings.CurrentUserTracker
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.LifecycleActivity
+import javax.inject.Inject
+
+class ControlsRequestDialog @Inject constructor(
+    private val controller: ControlsController,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val controlsListingController: ControlsListingController
+) : LifecycleActivity(), DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+
+    companion object {
+        private const val TAG = "ControlsRequestDialog"
+    }
+
+    private lateinit var component: ComponentName
+    private lateinit var control: Control
+    private var dialog: Dialog? = null
+    private val callback = object : ControlsListingController.ControlsListingCallback {
+        override fun onServicesUpdated(candidates: List<ControlsServiceInfo>) {}
+    }
+
+    private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
+        private val startingUser = controller.currentUserId
+
+        override fun onUserSwitched(newUserId: Int) {
+            if (newUserId != startingUser) {
+                stopTracking()
+                finish()
+            }
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        if (!controller.available) {
+            Log.w(TAG, "Quick Controls not available for this user ")
+            finish()
+        }
+        currentUserTracker.startTracking()
+        controlsListingController.addCallback(callback)
+
+        val requestUser = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL)
+        val currentUser = controller.currentUserId
+
+        if (requestUser != currentUser) {
+            Log.w(TAG, "Current user ($currentUser) different from request user ($requestUser)")
+            finish()
+        }
+
+        component = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME) ?: run {
+            Log.e(TAG, "Request did not contain componentName")
+            finish()
+            return
+        }
+
+        control = intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL) ?: run {
+            Log.e(TAG, "Request did not contain control")
+            finish()
+            return
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        val label = verifyComponentAndGetLabel()
+        if (label == null) {
+            Log.e(TAG, "The component specified (${component.flattenToString()} " +
+                    "is not a valid ControlsProviderService")
+            finish()
+            return
+        }
+
+        if (isCurrentFavorite()) {
+            Log.w(TAG, "The control ${control.title} is already a favorite")
+            finish()
+        }
+
+        dialog = createDialog(label)
+
+        dialog?.show()
+    }
+
+    override fun onDestroy() {
+        dialog?.dismiss()
+        currentUserTracker.stopTracking()
+        controlsListingController.removeCallback(callback)
+        super.onDestroy()
+    }
+
+    private fun verifyComponentAndGetLabel(): CharSequence? {
+        return controlsListingController.getAppLabel(component)
+    }
+
+    private fun isCurrentFavorite(): Boolean {
+        val favorites = controller.getFavoritesForComponent(component)
+        return favorites.any { it.controls.any { it.controlId == control.controlId } }
+    }
+
+    fun createDialog(label: CharSequence): Dialog {
+
+        val renderInfo = RenderInfo.lookup(control.deviceType, true)
+        val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
+            requireViewById<ImageView>(R.id.icon).apply {
+                setImageIcon(Icon.createWithResource(context, renderInfo.iconResourceId))
+                setImageTintList(
+                        context.resources.getColorStateList(renderInfo.foreground, context.theme))
+            }
+            requireViewById<TextView>(R.id.title).text = control.title
+            requireViewById<TextView>(R.id.subtitle).text = control.subtitle
+            requireViewById<View>(R.id.control).elevation =
+                    resources.getFloat(R.dimen.control_card_elevation)
+        }
+
+        val dialog = AlertDialog.Builder(this)
+                .setTitle(getString(R.string.controls_dialog_title))
+                .setMessage(getString(R.string.controls_dialog_message, label))
+                .setPositiveButton(R.string.controls_dialog_ok, this)
+                .setNegativeButton(android.R.string.cancel, this)
+                .setOnCancelListener(this)
+                .setView(frame)
+                .create()
+
+        SystemUIDialog.registerDismissListener(dialog)
+        dialog.setCanceledOnTouchOutside(true)
+        return dialog
+    }
+
+    override fun onCancel(dialog: DialogInterface?) {
+        finish()
+    }
+
+    override fun onClick(dialog: DialogInterface?, which: Int) {
+        if (which == Dialog.BUTTON_POSITIVE) {
+            controller.addFavorite(componentName, control.structure ?: "",
+                    ControlInfo(control.controlId, control.title, control.deviceType))
+        }
+        finish()
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
new file mode 100644
index 0000000..5c30b5a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.util.Log
+
+/**
+ * Proxy to launch in user 0
+ */
+class ControlsRequestReceiver : BroadcastReceiver() {
+
+    companion object {
+        private const val TAG = "ControlsRequestReceiver"
+
+        fun isPackageInForeground(context: Context, packageName: String): Boolean {
+            val uid = try {
+                context.packageManager.getPackageUid(packageName, 0)
+            } catch (_: PackageManager.NameNotFoundException) {
+                Log.w(TAG, "Package $packageName not found")
+                return false
+            }
+
+            val am = context.getSystemService(ActivityManager::class.java)
+            if ((am?.getUidImportance(uid) ?: IMPORTANCE_GONE) != IMPORTANCE_FOREGROUND) {
+                Log.w(TAG, "Uid $uid not in foreground")
+                return false
+            }
+            return true
+        }
+    }
+
+    override fun onReceive(context: Context, intent: Intent) {
+
+        val packageName = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
+                ?.packageName
+
+        if (packageName == null || !isPackageInForeground(context, packageName)) {
+            return
+        }
+
+        val activityIntent = Intent(context, ControlsRequestDialog::class.java).apply {
+            Intent.EXTRA_COMPONENT_NAME.let {
+                putExtra(it, intent.getParcelableExtra<ComponentName>(it))
+            }
+            ControlsProviderService.EXTRA_CONTROL.let {
+                putExtra(it, intent.getParcelableExtra<Control>(it))
+            }
+        }
+        activityIntent.putExtra(Intent.EXTRA_USER_ID, context.userId)
+
+        context.startActivityAsUser(activityIntent, UserHandle.SYSTEM)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index f2c8490..d56428d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -25,9 +25,9 @@
 import android.service.controls.actions.ControlAction
 import android.service.controls.templates.ControlTemplate
 import android.service.controls.templates.TemperatureControlTemplate
-import android.service.controls.templates.ThumbnailTemplate
 import android.service.controls.templates.ToggleRangeTemplate
 import android.service.controls.templates.ToggleTemplate
+import android.util.Log
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
@@ -97,15 +97,8 @@
     }
 
     fun actionResponse(@ControlAction.ResponseResult response: Int) {
-        val text = when (response) {
-            ControlAction.RESPONSE_OK -> "Success"
-            ControlAction.RESPONSE_FAIL -> "Error"
-            else -> ""
-        }
-
-        if (!text.isEmpty()) {
-            setTransientStatus(text)
-        }
+        // TODO: b/150931809 - handle response codes
+        Log.d(ControlsUiController.TAG, "Received response code: $response")
     }
 
     fun setTransientStatus(tempStatus: String) {
@@ -131,7 +124,6 @@
             template is ToggleTemplate -> ToggleBehavior::class
             template is ToggleRangeTemplate -> ToggleRangeBehavior::class
             template is TemperatureControlTemplate -> TemperatureControlBehavior::class
-            template is ThumbnailTemplate -> StaticBehavior::class
             else -> DefaultBehavior::class
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt
deleted file mode 100644
index c006d6f..0000000
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.controls.ui
-
-import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.LayerDrawable
-import android.service.controls.Control
-import android.service.controls.templates.ThumbnailTemplate
-
-import com.android.systemui.R
-import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL
-
-/**
- * Used for controls that cannot be interacted with. Information is presented to the user
- * but no actions can be taken. If using a ThumbnailTemplate, the background image will
- * be changed.
- */
-class StaticBehavior() : Behavior {
-    lateinit var control: Control
-    lateinit var cvh: ControlViewHolder
-
-    override fun initialize(cvh: ControlViewHolder) {
-        this.cvh = cvh
-    }
-
-    override fun bind(cws: ControlWithState) {
-        this.control = cws.control!!
-
-        cvh.status.setText(control.getStatusText())
-
-        val ld = cvh.layout.getBackground() as LayerDrawable
-        val clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
-
-        clipLayer.setLevel(MAX_LEVEL)
-        cvh.setEnabled(true)
-        cvh.applyRenderInfo(RenderInfo.lookup(control.getDeviceType(), true))
-
-        val template = control.getControlTemplate()
-        if (template is ThumbnailTemplate) {
-            cvh.bgExecutor.execute {
-                // clear the default tinting in favor of only using alpha
-                val drawable = template.getThumbnail().loadDrawable(cvh.context)
-                drawable.setTintList(null)
-                drawable.setAlpha((0.45 * 255).toInt())
-                cvh.uiExecutor.execute {
-                    val radius = cvh.context.getResources()
-                            .getDimensionPixelSize(R.dimen.control_corner_radius).toFloat()
-                    clipLayer.setDrawable(CornerDrawable(drawable, radius))
-                }
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 1fc1fe4..36b5fad 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -19,11 +19,8 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
-import android.annotation.MainThread;
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.RemoteException;
-import android.view.IWindowContainer;
 import android.view.SurfaceControl;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -61,31 +58,30 @@
                 com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
-    @MainThread
-    PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+    PipTransitionAnimator getAnimator(SurfaceControl leash, boolean scheduleFinishPip,
             Rect destinationBounds, float alphaStart, float alphaEnd) {
         if (mCurrentAnimator == null) {
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
-                            destinationBounds, alphaStart, alphaEnd));
+                    PipTransitionAnimator.ofAlpha(leash, scheduleFinishPip, destinationBounds,
+                            alphaStart, alphaEnd));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
                 && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.updateEndValue(alphaEnd);
         } else {
             mCurrentAnimator.cancel();
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
-                            destinationBounds, alphaStart, alphaEnd));
+                    PipTransitionAnimator.ofAlpha(leash, scheduleFinishPip, destinationBounds,
+                            alphaStart, alphaEnd));
         }
         return mCurrentAnimator;
     }
 
-    @MainThread
-    PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+    PipTransitionAnimator getAnimator(SurfaceControl leash, boolean scheduleFinishPip,
             Rect startBounds, Rect endBounds) {
         if (mCurrentAnimator == null) {
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
+                    PipTransitionAnimator.ofBounds(leash, scheduleFinishPip,
+                            startBounds, endBounds));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
                 && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.setDestinationBounds(endBounds);
@@ -94,7 +90,8 @@
         } else {
             mCurrentAnimator.cancel();
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
+                    PipTransitionAnimator.ofBounds(leash, scheduleFinishPip,
+                            startBounds, endBounds));
         }
         return mCurrentAnimator;
     }
@@ -116,18 +113,18 @@
         /**
          * Called when PiP animation is started.
          */
-        public void onPipAnimationStart(IWindowContainer wc, PipTransitionAnimator animator) {}
+        public void onPipAnimationStart(PipTransitionAnimator animator) {}
 
         /**
          * Called when PiP animation is ended.
          */
-        public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
+        public void onPipAnimationEnd(SurfaceControl.Transaction tx,
                 PipTransitionAnimator animator) {}
 
         /**
          * Called when PiP animation is cancelled.
          */
-        public void onPipAnimationCancel(IWindowContainer wc, PipTransitionAnimator animator) {}
+        public void onPipAnimationCancel(PipTransitionAnimator animator) {}
     }
 
     /**
@@ -137,7 +134,6 @@
     public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements
             ValueAnimator.AnimatorUpdateListener,
             ValueAnimator.AnimatorListener {
-        private final IWindowContainer mWindowContainer;
         private final boolean mScheduleFinishPip;
         private final SurfaceControl mLeash;
         private final @AnimationType int mAnimationType;
@@ -149,23 +145,18 @@
         private PipAnimationCallback mPipAnimationCallback;
         private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory;
 
-        private PipTransitionAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+        private PipTransitionAnimator(SurfaceControl leash, boolean scheduleFinishPip,
                 @AnimationType int animationType, Rect destinationBounds,
                 T startValue, T endValue) {
-            mWindowContainer = wc;
             mScheduleFinishPip = scheduleFinishPip;
-            try {
-                mLeash = wc.getLeash();
-                mAnimationType = animationType;
-                mDestinationBounds.set(destinationBounds);
-                mStartValue = startValue;
-                mEndValue = endValue;
-                addListener(this);
-                addUpdateListener(this);
-                mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+            mLeash = leash;
+            mAnimationType = animationType;
+            mDestinationBounds.set(destinationBounds);
+            mStartValue = startValue;
+            mEndValue = endValue;
+            addListener(this);
+            addUpdateListener(this);
+            mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
         }
 
         @Override
@@ -173,7 +164,7 @@
             mCurrentValue = mStartValue;
             applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), FRACTION_START);
             if (mPipAnimationCallback != null) {
-                mPipAnimationCallback.onPipAnimationStart(mWindowContainer, this);
+                mPipAnimationCallback.onPipAnimationStart(this);
             }
         }
 
@@ -189,14 +180,14 @@
             final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
             applySurfaceControlTransaction(mLeash, tx, FRACTION_END);
             if (mPipAnimationCallback != null) {
-                mPipAnimationCallback.onPipAnimationEnd(mWindowContainer, tx, this);
+                mPipAnimationCallback.onPipAnimationEnd(tx, this);
             }
         }
 
         @Override
         public void onAnimationCancel(Animator animation) {
             if (mPipAnimationCallback != null) {
-                mPipAnimationCallback.onPipAnimationCancel(mWindowContainer, this);
+                mPipAnimationCallback.onPipAnimationCancel(this);
             }
         }
 
@@ -260,9 +251,9 @@
         abstract void applySurfaceControlTransaction(SurfaceControl leash,
                 SurfaceControl.Transaction tx, float fraction);
 
-        static PipTransitionAnimator<Float> ofAlpha(IWindowContainer wc, boolean scheduleFinishPip,
+        static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash, boolean scheduleFinishPip,
                 Rect destinationBounds, float startValue, float endValue) {
-            return new PipTransitionAnimator<Float>(wc, scheduleFinishPip, ANIM_TYPE_ALPHA,
+            return new PipTransitionAnimator<Float>(leash, scheduleFinishPip, ANIM_TYPE_ALPHA,
                     destinationBounds, startValue, endValue) {
                 @Override
                 void applySurfaceControlTransaction(SurfaceControl leash,
@@ -281,10 +272,10 @@
             };
         }
 
-        static PipTransitionAnimator<Rect> ofBounds(IWindowContainer wc, boolean scheduleFinishPip,
+        static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, boolean scheduleFinishPip,
                 Rect startValue, Rect endValue) {
             // construct new Rect instances in case they are recycled
-            return new PipTransitionAnimator<Rect>(wc, scheduleFinishPip, ANIM_TYPE_BOUNDS,
+            return new PipTransitionAnimator<Rect>(leash, scheduleFinishPip, ANIM_TYPE_BOUNDS,
                     endValue, new Rect(startValue), new Rect(endValue)) {
                 private final Rect mTmpRect = new Rect();
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 1ae3d4f..fb348f4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -42,6 +42,8 @@
 
 import java.io.PrintWriter;
 
+import javax.inject.Inject;
+
 /**
  * Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
  * state changes originated from Window Manager and is the source of truth for PiP window bounds.
@@ -81,9 +83,10 @@
     private boolean mIsShelfShowing;
     private int mShelfHeight;
 
-    public PipBoundsHandler(Context context) {
+    @Inject
+    public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm) {
         mContext = context;
-        mSnapAlgorithm = new PipSnapAlgorithm(context);
+        mSnapAlgorithm = pipSnapAlgorithm;
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
         reloadResources();
         // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index 6bd28c5..6df6b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -25,6 +25,8 @@
 
 import java.io.PrintWriter;
 
+import javax.inject.Inject;
+
 /**
  * Calculates the snap targets and the snap position for the PIP given a position and a velocity.
  * All bounds are relative to the display top/left.
@@ -39,6 +41,7 @@
 
     private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
 
+    @Inject
     public PipSnapAlgorithm(Context context) {
         Resources res = context.getResources();
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 836485a..4766ebc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -30,6 +30,7 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.DisplayInfo;
@@ -38,9 +39,13 @@
 import android.view.SurfaceControl;
 import android.view.WindowContainerTransaction;
 
+import com.android.internal.os.SomeArgs;
+import com.android.systemui.pip.phone.PipUpdateThread;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * Manages PiP tasks such as resize and offset.
@@ -56,7 +61,13 @@
 public class PipTaskOrganizer extends ITaskOrganizer.Stub {
     private static final String TAG = PipTaskOrganizer.class.getSimpleName();
 
+    private static final int MSG_RESIZE_IMMEDIATE = 1;
+    private static final int MSG_RESIZE_ANIMATE = 2;
+    private static final int MSG_OFFSET_ANIMATE = 3;
+    private static final int MSG_FINISH_RESIZE = 4;
+
     private final Handler mMainHandler;
+    private final Handler mUpdateHandler;
     private final ITaskOrganizerController mTaskOrganizerController;
     private final PipBoundsHandler mPipBoundsHandler;
     private final PipAnimationController mPipAnimationController;
@@ -64,11 +75,11 @@
     private final Rect mDisplayBounds = new Rect();
     private final Rect mLastReportedBounds = new Rect();
 
+    // These callbacks are called on the update thread
     private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
             new PipAnimationController.PipAnimationCallback() {
         @Override
-        public void onPipAnimationStart(IWindowContainer wc,
-                PipAnimationController.PipTransitionAnimator animator) {
+        public void onPipAnimationStart(PipAnimationController.PipTransitionAnimator animator) {
             mMainHandler.post(() -> {
                 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                     final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -78,7 +89,7 @@
         }
 
         @Override
-        public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
+        public void onPipAnimationEnd(SurfaceControl.Transaction tx,
                 PipAnimationController.PipTransitionAnimator animator) {
             mMainHandler.post(() -> {
                 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
@@ -86,13 +97,11 @@
                     callback.onPipTransitionFinished();
                 }
             });
-            final Rect destinationBounds = animator.getDestinationBounds();
-            finishResizeInternal(destinationBounds, wc, tx, animator.shouldScheduleFinishPip());
+            finishResize(animator.getDestinationBounds(), tx, animator.shouldScheduleFinishPip());
         }
 
         @Override
-        public void onPipAnimationCancel(IWindowContainer wc,
-                PipAnimationController.PipTransitionAnimator animator) {
+        public void onPipAnimationCancel(PipAnimationController.PipTransitionAnimator animator) {
             mMainHandler.post(() -> {
                 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                     final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -102,28 +111,75 @@
         }
     };
 
+    private Handler.Callback mUpdateCallbacks = new Handler.Callback() {
+        @Override
+        public boolean handleMessage(Message msg) {
+            SomeArgs args = (SomeArgs) msg.obj;
+            Consumer<Rect> updateBoundsCallback = (Consumer<Rect>) args.arg1;
+            switch (msg.what) {
+                case MSG_RESIZE_IMMEDIATE: {
+                    Rect toBounds = (Rect) args.arg2;
+                    resizePip(toBounds);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+                case MSG_RESIZE_ANIMATE: {
+                    Rect currentBounds = (Rect) args.arg2;
+                    Rect toBounds = (Rect) args.arg3;
+                    boolean scheduleFinishPip = args.argi1 != 0;
+                    int duration = args.argi2;
+                    animateResizePip(scheduleFinishPip, currentBounds, toBounds, duration);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+                case MSG_OFFSET_ANIMATE: {
+                    Rect originalBounds = (Rect) args.arg2;
+                    final int offset = args.argi1;
+                    final int duration = args.argi2;
+                    offsetPip(originalBounds, 0 /* xOffset */, offset, duration);
+                    Rect toBounds = new Rect(originalBounds);
+                    toBounds.offset(0, offset);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+                case MSG_FINISH_RESIZE: {
+                    SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
+                    Rect toBounds = (Rect) args.arg3;
+                    boolean scheduleFinishPip = args.argi1 != 0;
+                    finishResize(toBounds, tx, scheduleFinishPip);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+            }
+            args.recycle();
+            return true;
+        }
+    };
+
     private ActivityManager.RunningTaskInfo mTaskInfo;
+    private IWindowContainer mToken;
+    private SurfaceControl mLeash;
+    private boolean mInPip;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
 
     public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) {
         mMainHandler = new Handler(Looper.getMainLooper());
+        mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
         mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController();
         mPipBoundsHandler = boundsHandler;
         mPipAnimationController = new PipAnimationController(context);
     }
 
-    /**
-     * Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
-     */
-    public void offsetPinnedStack(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
-        if (mTaskInfo == null) {
-            Log.w(TAG, "mTaskInfo is not set");
-            return;
-        }
-        final Rect destinationBounds = new Rect(originalBounds);
-        destinationBounds.offset(xOffset, yOffset);
-        animateResizePipInternal(mTaskInfo.token, false /* scheduleFinishPip*/,
-                originalBounds, destinationBounds, durationMs);
+    public Handler getUpdateHandler() {
+        return mUpdateHandler;
     }
 
     /**
@@ -171,7 +227,7 @@
         try {
             mLastReportedBounds.set(destinationBounds);
             final WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.setBounds(mTaskInfo.token, destinationBounds);
+            wct.setBounds(mToken, destinationBounds);
             mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to apply window container transaction", e);
@@ -185,13 +241,20 @@
                 getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
         mTaskInfo = info;
+        mToken = mTaskInfo.token;
+        mInPip = true;
+        try {
+            mLeash = mToken.getLeash();
+        } catch (RemoteException e) {
+            throw new RuntimeException("Unable to get leash", e);
+        }
         if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
             final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
-            animateResizePipInternal(mTaskInfo.token, true /* scheduleFinishPip */,
-                    currentBounds, destinationBounds, DURATION_DEFAULT_MS);
+            scheduleAnimateResizePip(true /* scheduleFinishPip */,
+                    currentBounds, destinationBounds, DURATION_DEFAULT_MS, null);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
-            mMainHandler.post(() -> mPipAnimationController
-                    .getAnimator(mTaskInfo.token, true /* scheduleFinishPip */,
+            mUpdateHandler.post(() -> mPipAnimationController
+                    .getAnimator(mLeash, true /* scheduleFinishPip */,
                             destinationBounds, 0f, 1f)
                     .setPipAnimationCallback(mPipAnimationCallback)
                     .setDuration(DURATION_DEFAULT_MS)
@@ -205,12 +268,12 @@
     @Override
     public void taskVanished(IWindowContainer token) {
         Objects.requireNonNull(token, "Requires valid IWindowContainer");
-        if (token.asBinder() != mTaskInfo.token.asBinder()) {
+        if (token.asBinder() != mToken.asBinder()) {
             Log.wtf(TAG, "Unrecognized token: " + token);
             return;
         }
-        animateResizePipInternal(token, false /* scheduleFinishPip */,
-                mLastReportedBounds, mDisplayBounds, DURATION_DEFAULT_MS);
+        scheduleAnimateResizePip(mDisplayBounds, DURATION_DEFAULT_MS, null);
+        mInPip = false;
     }
 
     @Override
@@ -227,7 +290,7 @@
         final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                 getAspectRatioOrDefault(newParams), null /* bounds */);
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
-        animateResizePip(destinationBounds, DURATION_DEFAULT_MS);
+        scheduleAnimateResizePip(destinationBounds, DURATION_DEFAULT_MS, null);
     }
 
     /**
@@ -243,102 +306,158 @@
     }
 
     /**
-     * Directly perform manipulation/resize on the leash. This will not perform any
-     * {@link WindowContainerTransaction} until {@link #finishResize} is called.
+     * Animates resizing of the pinned stack given the duration.
      */
-    public void resizePip(Rect destinationBounds) {
-        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
-        resizePipInternal(mTaskInfo.token, destinationBounds);
+    public void scheduleAnimateResizePip(Rect toBounds, int duration,
+            Consumer<Rect> updateBoundsCallback) {
+        scheduleAnimateResizePip(false /* scheduleFinishPip */,
+                mLastReportedBounds, toBounds, duration, updateBoundsCallback);
     }
 
-    private void resizePipInternal(IWindowContainer wc,
-            Rect destinationBounds) {
-        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
-        try {
-            // Could happen when dismissPip
-            if (wc == null || wc.getLeash() == null) {
-                Log.w(TAG, "Abort animation, invalid leash");
-                return;
-            }
-            final SurfaceControl leash = wc.getLeash();
-            new SurfaceControl.Transaction()
-                    .setPosition(leash, destinationBounds.left, destinationBounds.top)
-                    .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
-                    .apply();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Abort animation, invalid window container", e);
-        } catch (Exception e) {
-            Log.e(TAG, "Should not reach here, terrible thing happened", e);
+    private void scheduleAnimateResizePip(boolean scheduleFinishPip,
+            Rect currentBounds, Rect destinationBounds, int durationMs,
+            Consumer<Rect> updateBoundsCallback) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        if (!mInPip) {
+            // Ignore animation when we are no longer in PIP
+            return;
         }
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = currentBounds;
+        args.arg3 = destinationBounds;
+        args.argi1 = scheduleFinishPip ? 1 : 0;
+        args.argi2 = durationMs;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
+    }
+
+    /**
+     * Directly perform manipulation/resize on the leash. This will not perform any
+     * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
+     */
+    public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = toBounds;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
     }
 
     /**
      * Finish a intermediate resize operation. This is expected to be called after
-     * {@link #resizePip}.
+     * {@link #scheduleResizePip}.
      */
-    public void finishResize(Rect destinationBounds) {
-        try {
-            final IWindowContainer wc = mTaskInfo.token;
-            SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
-                    .setPosition(wc.getLeash(), destinationBounds.left,
-                            destinationBounds.top)
-                    .setWindowCrop(wc.getLeash(), destinationBounds.width(),
-                            destinationBounds.height());
-            finishResizeInternal(destinationBounds, wc, tx, false);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to obtain leash");
-        }
+    public void scheduleFinishResizePip(Rect destinationBounds) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
+                .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
+                .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
+        scheduleFinishResizePip(tx, destinationBounds, false /* scheduleFinishPip */,
+                null);
     }
 
-    private void finishResizeInternal(Rect destinationBounds, IWindowContainer wc,
-            SurfaceControl.Transaction tx, boolean shouldScheduleFinishPip) {
+    private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
+            Rect destinationBounds, boolean scheduleFinishPip,
+            Consumer<Rect> updateBoundsCallback) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = tx;
+        args.arg3 = destinationBounds;
+        args.argi1 = scheduleFinishPip ? 1 : 0;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args));
+    }
+
+    /**
+     * Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
+     */
+    public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
+            Consumer<Rect> updateBoundsCallback) {
+        if (!mInPip) {
+            // Ignore offsets when we are no longer in PIP
+            return;
+        }
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = originalBounds;
+        // offset would be zero if triggered from screen rotation.
+        args.argi1 = offset;
+        args.argi2 = duration;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
+    }
+
+    private void offsetPip(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleOffsetPip() instead of this "
+                    + "directly");
+        }
+        if (mTaskInfo == null) {
+            Log.w(TAG, "mTaskInfo is not set");
+            return;
+        }
+        final Rect destinationBounds = new Rect(originalBounds);
+        destinationBounds.offset(xOffset, yOffset);
+        animateResizePip(false /* scheduleFinishPip*/, originalBounds, destinationBounds,
+                durationMs);
+    }
+
+    private void resizePip(Rect destinationBounds) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+                    + "directly");
+        }
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        // Could happen when dismissPip
+        if (mToken == null || mLeash == null) {
+            Log.w(TAG, "Abort animation, invalid leash");
+            return;
+        }
+        new SurfaceControl.Transaction()
+                .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
+                .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
+                .apply();
+    }
+
+    private void finishResize(Rect destinationBounds, SurfaceControl.Transaction tx,
+            boolean shouldScheduleFinishPip) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+                    + "directly");
+        }
         mLastReportedBounds.set(destinationBounds);
         try {
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             if (shouldScheduleFinishPip) {
-                wct.scheduleFinishEnterPip(wc, destinationBounds);
+                wct.scheduleFinishEnterPip(mToken, destinationBounds);
             } else {
-                wct.setBounds(wc, destinationBounds);
+                wct.setBounds(mToken, destinationBounds);
             }
-            wct.setBoundsChangeTransaction(mTaskInfo.token, tx);
+            wct.setBoundsChangeTransaction(mToken, tx);
             mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to apply container transaction", e);
         }
     }
 
-    /**
-     * Animates resizing of the pinned stack given the duration.
-     */
-    public void animateResizePip(Rect destinationBounds, int durationMs) {
-        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
-        animateResizePipInternal(mTaskInfo.token, false, mLastReportedBounds,
-                destinationBounds, durationMs);
-    }
-
-    private void animateResizePipInternal(IWindowContainer wc, boolean scheduleFinishPip,
-            Rect currentBounds, Rect destinationBounds, int durationMs) {
-        try {
-            // Could happen when dismissPip
-            if (wc == null || wc.getLeash() == null) {
-                Log.w(TAG, "Abort animation, invalid leash");
-                return;
-            }
-            final SurfaceControl leash = wc.getLeash();
-
-            mMainHandler.post(() -> mPipAnimationController
-                    .getAnimator(wc, scheduleFinishPip, currentBounds, destinationBounds)
-                    .setPipAnimationCallback(mPipAnimationCallback)
-                    .setDuration(durationMs)
-                    .start());
-        } catch (RemoteException e) {
-            Log.w(TAG, "Abort animation, invalid window container", e);
-        } catch (Exception e) {
-            Log.e(TAG, "Should not reach here, terrible thing happened", e);
+    private void animateResizePip(boolean scheduleFinishPip, Rect currentBounds,
+            Rect destinationBounds, int durationMs) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
+                    + "this directly");
         }
+        // Could happen when dismissPip
+        if (mToken == null || mLeash == null) {
+            Log.w(TAG, "Abort animation, invalid leash");
+            return;
+        }
+        mUpdateHandler.post(() -> mPipAnimationController
+                .getAnimator(mLeash, scheduleFinishPip, currentBounds, destinationBounds)
+                .setPipAnimationCallback(mPipAnimationCallback)
+                .setDuration(durationMs)
+                .start());
     }
 
-
     private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
         return params == null
                 ? mPipBoundsHandler.getDefaultAspectRatio()
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 8ada3c3..4b97d13 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -41,6 +41,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -205,7 +206,9 @@
     public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
             DisplayController displayController,
             FloatingContentCoordinator floatingContentCoordinator,
-            DeviceConfigProxy deviceConfig) {
+            DeviceConfigProxy deviceConfig,
+            PipBoundsHandler pipBoundsHandler,
+            PipSnapAlgorithm pipSnapAlgorithm) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
 
@@ -218,7 +221,7 @@
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
         final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
-        mPipBoundsHandler = new PipBoundsHandler(context);
+        mPipBoundsHandler = pipBoundsHandler;
         mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mInputConsumerController = InputConsumerController.getPipInputConsumer();
@@ -227,7 +230,7 @@
                 mInputConsumerController);
         mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager,
                 mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
-                floatingContentCoordinator, deviceConfig);
+                floatingContentCoordinator, deviceConfig, pipSnapAlgorithm);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
         displayController.addDisplayChangingController(mRotationController);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 81e8a0b..fc04f79 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -60,6 +60,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -226,6 +227,15 @@
     }
 
     @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+            hideMenu();
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
         updateFromIntent(intent);
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 fdaf66a..33760be 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -28,16 +28,11 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Debug;
-import android.os.Handler;
-import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.Choreographer;
 
 import androidx.dynamicanimation.animation.SpringForce;
 
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.os.SomeArgs;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -47,11 +42,12 @@
 import com.android.systemui.util.animation.PhysicsAnimator;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * A helper to animate and manipulate the PiP.
  */
-public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback,
+public class PipMotionHelper implements PipAppOpsListener.Callback,
         FloatingContentCoordinator.FloatingContent {
 
     private static final String TAG = "PipMotionHelper";
@@ -68,14 +64,9 @@
     // The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
     private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
 
-    private static final int MSG_RESIZE_IMMEDIATE = 1;
-    private static final int MSG_RESIZE_ANIMATE = 2;
-    private static final int MSG_OFFSET_ANIMATE = 3;
-
     private final Context mContext;
     private final IActivityTaskManager mActivityTaskManager;
     private final PipTaskOrganizer mPipTaskOrganizer;
-    private final Handler mHandler;
 
     private PipMenuActivityController mMenuController;
     private PipSnapAlgorithm mSnapAlgorithm;
@@ -92,9 +83,6 @@
     /** The region that all of PIP must stay within. */
     private Rect mFloatingAllowedArea = new Rect();
 
-    private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
-            new SfVsyncFrameCallbackProvider();
-
     /**
      * Bounds that are animated using the physics animator.
      */
@@ -112,16 +100,11 @@
     private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
             mAnimatedBounds);
 
-    /** Callback that re-sizes PIP to the animated bounds. */
-    private final Choreographer.FrameCallback mResizePipVsyncCallback =
-            l -> resizePipUnchecked(mAnimatedBounds);
-
     /**
-     * Update listener that posts a vsync frame callback to resize PIP to {@link #mAnimatedBounds}.
+     * Update listener that resizes the PIP to {@link #mAnimatedBounds}.
      */
-    private final PhysicsAnimator.UpdateListener<Rect> mResizePipVsyncUpdateListener =
-            (target, values) ->
-                    mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
+    private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
+            (target, values) -> resizePipUnchecked(mAnimatedBounds);
 
     /** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
     private PhysicsAnimator.FlingConfig mFlingConfigX;
@@ -137,12 +120,13 @@
                 new PhysicsAnimator.SpringConfig(
                         SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
 
+    private final Consumer<Rect> mUpdateBoundsCallback = (toBounds) -> mBounds.set(toBounds);
+
     public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
             PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
             PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
             FloatingContentCoordinator floatingContentCoordinator) {
         mContext = context;
-        mHandler = new Handler(ForegroundThread.get().getLooper(), this);
         mActivityTaskManager = activityTaskManager;
         mPipTaskOrganizer = pipTaskOrganizer;
         mMenuController = menuController;
@@ -234,7 +218,7 @@
         }
         cancelAnimations();
         mMenuController.hideMenuWithoutResize();
-        mHandler.post(() -> {
+        mPipTaskOrganizer.getUpdateHandler().post(() -> {
             try {
                 mActivityTaskManager.dismissPip(!skipAnimation, EXPAND_STACK_TO_FULLSCREEN_DURATION);
             } catch (RemoteException e) {
@@ -253,7 +237,7 @@
         }
         cancelAnimations();
         mMenuController.hideMenuWithoutResize();
-        mHandler.post(() -> {
+        mPipTaskOrganizer.getUpdateHandler().post(() -> {
             try {
                 mActivityTaskManager.removeStacksInWindowingModes(
                         new int[]{ WINDOWING_MODE_PINNED });
@@ -406,17 +390,13 @@
      * Animates the PiP to offset it from the IME or shelf.
      */
     void animateToOffset(Rect originalBounds, int offset) {
+        if (DEBUG) {
+            Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
+                    + " callers=\n" + Debug.getCallers(5, "    "));
+        }
         cancelAnimations();
-        adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION);
-    }
-
-    private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
-        SomeArgs args = SomeArgs.obtain();
-        args.arg1 = originalBounds;
-        // offset would be zero if triggered from screen rotation.
-        args.argi1 = offset;
-        args.argi2 = duration;
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
+        mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
+                mUpdateBoundsCallback);
     }
 
     /**
@@ -437,8 +417,7 @@
 
     /**
      * Starts the physics animator which will update the animated PIP bounds using physics
-     * animations, as well as the TimeAnimator which will apply those bounds to PIP at intervals
-     * synchronized with the SurfaceFlinger vsync frame provider.
+     * animations, as well as the TimeAnimator which will apply those bounds to PIP.
      *
      * This will also add end actions to the bounds animator that cancel the TimeAnimator and update
      * the 'real' bounds to equal the final animated bounds.
@@ -448,7 +427,7 @@
 
         mAnimatedBoundsPhysicsAnimator
                 .withEndActions(() ->  mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds))
-                .addUpdateListener(mResizePipVsyncUpdateListener)
+                .addUpdateListener(mResizePipUpdateListener)
                 .start();
     }
 
@@ -471,9 +450,7 @@
                     + " callers=\n" + Debug.getCallers(5, "    "));
         }
         if (!toBounds.equals(mBounds)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = toBounds;
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
+            mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback);
         }
     }
 
@@ -486,10 +463,7 @@
                     + " duration=" + duration + " callers=\n" + Debug.getCallers(5, "    "));
         }
         if (!toBounds.equals(mBounds)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = toBounds;
-            args.argi1 = duration;
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
+            mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
             setAnimatingToBounds(toBounds);
         }
     }
@@ -538,70 +512,6 @@
         return dismissArea.contains(endpoint.x, endpoint.y);
     }
 
-    /**
-     * Handles messages to be processed on the background thread.
-     */
-    public boolean handleMessage(Message msg) {
-        switch (msg.what) {
-            case MSG_RESIZE_IMMEDIATE: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                Rect toBounds = (Rect) args.arg1;
-                mPipTaskOrganizer.resizePip(toBounds);
-                mBounds.set(toBounds);
-                return true;
-            }
-
-            case MSG_RESIZE_ANIMATE: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                Rect toBounds = (Rect) args.arg1;
-                int duration = args.argi1;
-                try {
-                    StackInfo stackInfo = mActivityTaskManager.getStackInfo(
-                            WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-                    if (stackInfo == null) {
-                        // In the case where we've already re-expanded or dismissed the PiP, then
-                        // just skip the resize
-                        return true;
-                    }
-
-                    mPipTaskOrganizer.animateResizePip(toBounds, duration);
-                    mBounds.set(toBounds);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
-                }
-                return true;
-            }
-
-            case MSG_OFFSET_ANIMATE: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                Rect originalBounds = (Rect) args.arg1;
-                final int offset = args.argi1;
-                final int duration = args.argi2;
-                try {
-                    StackInfo stackInfo = mActivityTaskManager.getStackInfo(
-                            WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-                    if (stackInfo == null) {
-                        // In the case where we've already re-expanded or dismissed the PiP, then
-                        // just skip the resize
-                        return true;
-                    }
-
-                    mPipTaskOrganizer.offsetPinnedStack(originalBounds,
-                            0 /* xOffset */, offset, duration);
-                    Rect toBounds = new Rect(originalBounds);
-                    toBounds.offset(0, offset);
-                    mBounds.set(toBounds);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e);
-                }
-                return true;
-            }
-
-            default:
-                return false;
-        }
-    }
-
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
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 c3212b8..90db91a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -166,7 +166,8 @@
             PipBoundsHandler pipBoundsHandler,
             PipTaskOrganizer pipTaskOrganizer,
             FloatingContentCoordinator floatingContentCoordinator,
-            DeviceConfigProxy deviceConfig) {
+            DeviceConfigProxy deviceConfig,
+            PipSnapAlgorithm pipSnapAlgorithm) {
         // Initialize the Pip input consumer
         mContext = context;
         mActivityManager = activityManager;
@@ -174,7 +175,7 @@
         mMenuController = menuController;
         mMenuController.addListener(new PipMenuListener());
         mDismissViewController = new PipDismissViewController(context);
-        mSnapAlgorithm = new PipSnapAlgorithm(mContext);
+        mSnapAlgorithm = pipSnapAlgorithm;
         mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
                 2.5f);
         mGesture = new DefaultPipTouchGesture();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
rename to packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
index 9bf46bb..6c5d846 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
@@ -21,33 +21,38 @@
 
 /**
  * Similar to {@link com.android.internal.os.BackgroundThread}, this is a shared singleton
- * foreground thread for each process.
+ * foreground thread for each process for updating PIP.
  */
-public final class ForegroundThread extends HandlerThread {
-    private static ForegroundThread sInstance;
+public final class PipUpdateThread extends HandlerThread {
+    private static PipUpdateThread sInstance;
     private static Handler sHandler;
 
-    private ForegroundThread() {
-        super("recents.fg");
+    private PipUpdateThread() {
+        super("pip");
     }
 
     private static void ensureThreadLocked() {
         if (sInstance == null) {
-            sInstance = new ForegroundThread();
+            sInstance = new PipUpdateThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
         }
     }
 
-    public static ForegroundThread get() {
-        synchronized (ForegroundThread.class) {
+    /**
+     * @return the static update thread instance
+     */
+    public static PipUpdateThread get() {
+        synchronized (PipUpdateThread.class) {
             ensureThreadLocked();
             return sInstance;
         }
     }
-
+    /**
+     * @return the static update thread handler instance
+     */
     public static Handler getHandler() {
-        synchronized (ForegroundThread.class) {
+        synchronized (PipUpdateThread.class) {
             ensureThreadLocked();
             return sHandler;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index f28c3f6..a5e9dbc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,6 +20,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
+import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
+
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
@@ -50,7 +52,6 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.PipAnimationController;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -228,13 +229,15 @@
     }
 
     @Inject
-    public PipManager(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
+            PipBoundsHandler pipBoundsHandler) {
         if (mInitialized) {
             return;
         }
+
         mInitialized = true;
         mContext = context;
-        mPipBoundsHandler = new PipBoundsHandler(context);
+        mPipBoundsHandler = pipBoundsHandler;
         mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mActivityTaskManager = ActivityTaskManager.getService();
@@ -433,8 +436,7 @@
                 mCurrentPipBounds = mPipBounds;
                 break;
         }
-        mPipTaskOrganizer.animateResizePip(mCurrentPipBounds,
-                PipAnimationController.DURATION_DEFAULT_MS);
+        mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, DURATION_DEFAULT_MS, null);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 37a8ca5..8b8b6f8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -16,10 +16,6 @@
 
 package com.android.systemui.screenshot;
 
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
-
 import android.app.Service;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -33,7 +29,6 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.provider.DeviceConfig;
 import android.util.Log;
 import android.view.WindowManager;
 
@@ -70,8 +65,7 @@
             }
 
             // TODO (mkephart): clean up once notifications flow is fully deprecated
-            boolean useCornerFlow = DeviceConfig.getBoolean(
-                    NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, true);
+            boolean useCornerFlow = true;
             switch (msg.what) {
                 case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                     if (useCornerFlow) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 333fa3c..c6eecf26 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,6 +17,8 @@
 package com.android.systemui.stackdivider;
 
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.animation.Animator;
@@ -214,8 +216,22 @@
                     if (mTargetAdjusted) {
                         mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
                         wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+                        // "Freeze" the configuration size so that the app doesn't get a config
+                        // or relaunch. This is required because normally nav-bar contributes
+                        // to configuration bounds (via nondecorframe).
+                        Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
+                                .windowConfiguration.getAppBounds());
+                        adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
+                                - mSplitLayout.mSecondary.top);
+                        wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
+                        wct.setScreenSizeDp(mSplits.mSecondary.token,
+                                mSplits.mSecondary.configuration.screenWidthDp,
+                                mSplits.mSecondary.configuration.screenHeightDp);
                     } else {
                         wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+                        wct.setAppBounds(mSplits.mSecondary.token, null);
+                        wct.setScreenSizeDp(mSplits.mSecondary.token,
+                                SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
                     }
                     try {
                         ActivityTaskManager.getTaskOrganizerController()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 9c942a5..8674047 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -27,6 +27,9 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
@@ -72,11 +75,14 @@
         val aRank = a.ranking.rank
         val bRank = b.ranking.rank
 
-        val aIsPeople = a.isPeopleNotification()
-        val bIsPeople = b.isPeopleNotification()
+        val aPersonType = a.getPeopleNotificationType()
+        val bPersonType = b.getPeopleNotificationType()
 
-        val aIsImportantPeople = a.isImportantPeopleNotification()
-        val bIsImportantPeople = b.isImportantPeopleNotification()
+        val aIsPeople = aPersonType == TYPE_PERSON
+        val bIsPeople = bPersonType == TYPE_PERSON
+
+        val aIsImportantPeople = aPersonType == TYPE_IMPORTANT_PERSON
+        val bIsImportantPeople = bPersonType == TYPE_IMPORTANT_PERSON
 
         val aMedia = isImportantMedia(a)
         val bMedia = isImportantMedia(b)
@@ -165,7 +171,7 @@
     ) {
         if (usePeopleFiltering && isHeadsUp) {
             entry.bucket = BUCKET_HEADS_UP
-        } else if (usePeopleFiltering && entry.isPeopleNotification()) {
+        } else if (usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON) {
             entry.bucket = BUCKET_PEOPLE
         } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
             entry.bucket = BUCKET_ALERTING
@@ -198,11 +204,8 @@
         }
     }
 
-    private fun NotificationEntry.isPeopleNotification() =
-            peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)
-
-    private fun NotificationEntry.isImportantPeopleNotification() =
-            peopleNotificationIdentifier.isImportantPeopleNotification(sbn, ranking)
+    private fun NotificationEntry.getPeopleNotificationType() =
+            peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
 
     private fun NotificationEntry.isHighPriority() =
             highPriorityProvider.isHighPriority(this)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 0d9beae..df3609b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -103,8 +103,8 @@
     }
 
     private boolean isPeopleNotification(NotificationEntry entry) {
-        return mPeopleNotificationIdentifier.isPeopleNotification(
-                entry.getSbn(), entry.getRanking());
+        return mPeopleNotificationIdentifier.getPeopleNotificationType(
+                entry.getSbn(), entry.getRanking()) != PeopleNotificationIdentifier.TYPE_NON_PERSON;
     }
 
     private boolean hasUserSetImportance(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
index 3007198..3af6ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.people
 
-import android.app.PendingIntent
 import android.graphics.drawable.Drawable
 
 /**
@@ -45,10 +44,11 @@
 /** `Model` for a single "Person" in PeopleHub. */
 data class PersonModel(
     val key: PersonKey,
+    val userId: Int,
+    // TODO: these should live in the ViewModel
     val name: CharSequence,
     val avatar: Drawable,
-    val clickRunnable: Runnable,
-    val userId: Int
+    val clickRunnable: Runnable
 )
 
 /** Unique identifier for a Person in PeopleHub. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index 360bf96..2fbd3ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -20,9 +20,7 @@
 import android.content.Context
 import android.content.pm.LauncherApps
 import android.content.pm.PackageManager
-import android.content.pm.ShortcutInfo
 import android.content.pm.UserInfo
-import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
 import android.os.UserManager
 import android.service.notification.NotificationListenerService
@@ -45,6 +43,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryListener
 import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
 import com.android.systemui.statusbar.policy.ExtensionController
 import java.util.ArrayDeque
 import java.util.concurrent.Executor
@@ -79,7 +78,7 @@
 
     override fun extractPerson(sbn: StatusBarNotification) =
             plugin?.extractPerson(sbn)?.run {
-                PersonModel(key, name, avatar, clickRunnable, sbn.user.identifier)
+                PersonModel(key, sbn.user.identifier, name, avatar, clickRunnable)
             }
 
     override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
@@ -90,26 +89,35 @@
 
 @Singleton
 class PeopleHubDataSourceImpl @Inject constructor(
-        private val notificationEntryManager: NotificationEntryManager,
-        private val extractor: NotificationPersonExtractor,
-        private val userManager: UserManager,
-        private val launcherApps: LauncherApps,
-        private val packageManager: PackageManager,
-        private val c: Context,
-        private val notificationListener: NotificationListener,
-        @Background private val bgExecutor: Executor,
-        @Main private val mainExecutor: Executor,
-        private val notifLockscreenUserMgr: NotificationLockscreenUserManager,
-        private val peopleNotificationIdentifier: PeopleNotificationIdentifier
-        ) : DataSource<PeopleHubModel> {
+    private val notificationEntryManager: NotificationEntryManager,
+    private val extractor: NotificationPersonExtractor,
+    private val userManager: UserManager,
+    launcherApps: LauncherApps,
+    packageManager: PackageManager,
+    context: Context,
+    private val notificationListener: NotificationListener,
+    @Background private val bgExecutor: Executor,
+    @Main private val mainExecutor: Executor,
+    private val notifLockscreenUserMgr: NotificationLockscreenUserManager,
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier
+) : DataSource<PeopleHubModel> {
 
     private var userChangeSubscription: Subscription? = null
     private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
     private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
-    val context: Context = c.applicationContext
-    val iconFactory = ConversationIconFactory(context, launcherApps, packageManager,
-            IconDrawableFactory.newInstance(context), context.resources.getDimensionPixelSize(
-            R.dimen.notification_guts_conversation_icon_size))
+
+    private val iconFactory = run {
+        val appContext = context.applicationContext
+        ConversationIconFactory(
+                appContext,
+                launcherApps,
+                packageManager,
+                IconDrawableFactory.newInstance(appContext),
+                appContext.resources.getDimensionPixelSize(
+                        R.dimen.notification_guts_conversation_icon_size
+                )
+        )
+    }
 
     private val notificationEntryListener = object : NotificationEntryListener {
         override fun onEntryInflated(entry: NotificationEntry) = addVisibleEntry(entry)
@@ -206,7 +214,8 @@
     }
 
     private fun NotificationEntry.extractPerson(): PersonModel? {
-        if (!peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) {
+        val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+        if (type == TYPE_NON_PERSON) {
             return null
         }
         val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) }
@@ -215,23 +224,34 @@
                 ?: extras.getString(Notification.EXTRA_CONVERSATION_TITLE)
                 ?: extras.getString(Notification.EXTRA_TITLE)
                 ?: return null
-        val drawable = ranking.shortcutInfo?.getIcon(iconFactory, sbn, ranking)
-                ?: iconFactory.getConversationDrawable(extractAvatarFromRow(this), sbn.packageName,
-                        sbn.uid, ranking.channel.isImportantConversation)
-
-        return PersonModel(key, name, drawable, clickRunnable, sbn.user.identifier)
+        val drawable = ranking.getIcon(iconFactory, sbn)
+                ?: iconFactory.getConversationDrawable(
+                        extractAvatarFromRow(this),
+                        sbn.packageName,
+                        sbn.uid,
+                        ranking.channel.isImportantConversation
+                )
+        return PersonModel(key, sbn.user.identifier, name, drawable, clickRunnable)
     }
 
-    private fun ShortcutInfo.getIcon(iconFactory: ConversationIconFactory,
-                                     sbn: StatusBarNotification,
-                                     ranking: NotificationListenerService.Ranking): Drawable? {
-        return iconFactory.getConversationDrawable(ranking.shortcutInfo, sbn.packageName, sbn.uid,
-                ranking.channel.isImportantConversation)
-    }
+    private fun NotificationListenerService.Ranking.getIcon(
+        iconFactory: ConversationIconFactory,
+        sbn: StatusBarNotification
+    ): Drawable? =
+            shortcutInfo?.let { shortcutInfo ->
+                iconFactory.getConversationDrawable(
+                        shortcutInfo,
+                        sbn.packageName,
+                        sbn.uid,
+                        channel.isImportantConversation
+                )
+            }
 
-    private fun NotificationEntry.extractPersonKey(): PersonKey? =
-            // TODO migrate to shortcut id when snoozing is conversation wide
-            if (peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) key else null
+    private fun NotificationEntry.extractPersonKey(): PersonKey? {
+        // TODO migrate to shortcut id when snoozing is conversation wide
+        val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+        return if (type != TYPE_NON_PERSON) key else null
+    }
 }
 
 private fun NotificationLockscreenUserManager.registerListener(
@@ -303,4 +323,3 @@
                             ?.drawable
                 }
                 ?.firstOrNull()
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index e15fa2e..597bdb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -16,24 +16,97 @@
 
 package com.android.systemui.statusbar.notification.people
 
+import android.annotation.IntDef
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.StatusBarNotification
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.statusbar.phone.NotificationGroupManager
 import javax.inject.Inject
 import javax.inject.Singleton
+import kotlin.math.max
 
 interface PeopleNotificationIdentifier {
-    fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean
-    fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean
+
+    /**
+     * Identifies if the given notification can be classified as a "People" notification.
+     *
+     * @return [TYPE_NON_PERSON] if not a people notification, [TYPE_PERSON] if a standard people
+     *  notification, and [TYPE_IMPORTANT_PERSON] if an "important" people notification.
+     */
+    @PeopleNotificationType
+    fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int
+
+    companion object {
+
+        @Retention(AnnotationRetention.SOURCE)
+        @IntDef(prefix = ["TYPE_"], value = [TYPE_NON_PERSON, TYPE_PERSON, TYPE_IMPORTANT_PERSON])
+        annotation class PeopleNotificationType
+
+        const val TYPE_NON_PERSON = 0
+        const val TYPE_PERSON = 1
+        const val TYPE_IMPORTANT_PERSON = 2
+    }
 }
 
 @Singleton
 class PeopleNotificationIdentifierImpl @Inject constructor(
-    private val personExtractor: NotificationPersonExtractor
+    private val personExtractor: NotificationPersonExtractor,
+    private val groupManager: NotificationGroupManager
 ) : PeopleNotificationIdentifier {
 
-    override fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) =
-            ranking.isConversation || personExtractor.isPersonNotification(sbn)
+    @PeopleNotificationType
+    override fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int =
+            when (val type = ranking.personTypeInfo) {
+                TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
+                else -> {
+                    when (val type = upperBound(type, extractPersonTypeInfo(sbn))) {
+                        TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
+                        else -> upperBound(type, getPeopleTypeOfSummary(sbn))
+                    }
+                }
+            }
 
-    override fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) =
-            isPeopleNotification(sbn, ranking) && ranking.channel.isImportantConversation
-}
\ No newline at end of file
+    /**
+     * Given two [PeopleNotificationType]s, determine the upper bound. Used to constrain a
+     * notification to a type given multiple signals, i.e. notification groups, where each child
+     * has a [PeopleNotificationType] that is used to constrain the summary.
+     */
+    @PeopleNotificationType
+    private fun upperBound(
+        @PeopleNotificationType type: Int,
+        @PeopleNotificationType other: Int
+    ): Int =
+            max(type, other)
+
+    private val Ranking.personTypeInfo
+        get() = when {
+            channel.isImportantConversation -> TYPE_IMPORTANT_PERSON
+            isConversation -> TYPE_PERSON
+            else -> TYPE_NON_PERSON
+        }
+
+    private fun extractPersonTypeInfo(sbn: StatusBarNotification) =
+            if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON
+
+    private fun getPeopleTypeOfSummary(statusBarNotification: StatusBarNotification): Int {
+        if (!groupManager.isSummaryOfGroup(statusBarNotification)) {
+            return TYPE_NON_PERSON
+        }
+
+        val childTypes = groupManager.getLogicalChildren(statusBarNotification)
+                ?.asSequence()
+                ?.map { getPeopleNotificationType(it.sbn, it.ranking) }
+                ?: return TYPE_NON_PERSON
+
+        var groupType = TYPE_NON_PERSON
+        for (childType in childTypes) {
+            groupType = upperBound(groupType, childType)
+            if (groupType == TYPE_IMPORTANT_PERSON)
+                break
+        }
+        return groupType
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index d746822..bd4984e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -315,7 +315,6 @@
                     mNotificationActivityStarter.startNotificationGutsIntent(intent, sbn.getUid(),
                             row);
                 };
-        boolean isForBlockingHelper = row.isBlockingHelperShowing();
 
         if (!userHandle.equals(UserHandle.ALL)
                 || mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
@@ -335,13 +334,10 @@
                 row.getEntry().getChannel(),
                 row.getUniqueChannels(),
                 row.getEntry(),
-                mCheckSaveListener,
                 onSettingsClick,
                 onAppSettingsClick,
                 mDeviceProvisionedController.isDeviceProvisioned(),
                 row.getIsNonblockable(),
-                isForBlockingHelper,
-                row.getEntry().getImportance(),
                 mHighPriorityProvider.isHighPriority(row.getEntry()));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 6b4511d..12aa4df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -24,10 +24,6 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.INotificationManager;
@@ -53,7 +49,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -63,42 +58,33 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 
 import java.lang.annotation.Retention;
 import java.util.List;
 import java.util.Set;
 
 /**
- * The guts of a notification revealed when performing a long press. This also houses the blocking
- * helper affordance that allows a user to keep/stop notifications after swiping one away.
+ * The guts of a notification revealed when performing a long press.
  */
 public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
     private static final String TAG = "InfoGuts";
 
     @IntDef(prefix = { "ACTION_" }, value = {
             ACTION_NONE,
-            ACTION_UNDO,
+            ACTION_TOGGLE_ALERT,
             ACTION_TOGGLE_SILENT,
-            ACTION_BLOCK,
     })
     public @interface NotificationInfoAction {
     }
 
     public static final int ACTION_NONE = 0;
-    static final int ACTION_UNDO = 1;
     // standard controls
     static final int ACTION_TOGGLE_SILENT = 2;
-    // unused
-    static final int ACTION_BLOCK = 3;
-    // blocking helper
-    static final int ACTION_DELIVER_SILENTLY = 4;
     // standard controls
-    private static final int ACTION_ALERT = 5;
+    private static final int ACTION_TOGGLE_ALERT = 5;
 
     private TextView mPriorityDescriptionView;
     private TextView mSilentDescriptionView;
@@ -128,101 +114,35 @@
     @Nullable private Integer mChosenImportance;
     private boolean mIsSingleDefaultChannel;
     private boolean mIsNonblockable;
-    private NotificationEntry mEntry;
     private StatusBarNotification mSbn;
-    private AnimatorSet mExpandAnimation;
     private boolean mIsDeviceProvisioned;
 
-    private CheckSaveListener mCheckSaveListener;
     private OnSettingsClickListener mOnSettingsClickListener;
     private OnAppSettingsClickListener mAppSettingsClickListener;
     private NotificationGuts mGutsContainer;
     private Drawable mPkgIcon;
 
-    /** Whether this view is being shown as part of the blocking helper. */
-    private boolean mIsForBlockingHelper;
-
     @VisibleForTesting
     boolean mSkipPost = false;
 
-    /**
-     * String that describes how the user exit or quit out of this view, also used as a counter tag.
-     */
-    private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
-
-
     // used by standard ui
     private OnClickListener mOnAlert = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
         mChosenImportance = IMPORTANCE_DEFAULT;
         applyAlertingBehavior(BEHAVIOR_ALERTING, true /* userTriggered */);
     };
 
     // used by standard ui
     private OnClickListener mOnSilent = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
         mChosenImportance = IMPORTANCE_LOW;
         applyAlertingBehavior(BEHAVIOR_SILENT, true /* userTriggered */);
     };
 
-
     // used by standard ui
     private OnClickListener mOnDismissSettings = v -> {
         mPressedApply = true;
         closeControls(v, true);
     };
 
-    // used by blocking helper
-    private OnClickListener mOnKeepShowing = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
-        closeControls(v, true);
-        mMetricsLogger.write(getLogMaker().setCategory(
-                MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
-                .setType(MetricsEvent.TYPE_ACTION)
-                .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
-    };
-
-    // used by blocking helper
-    private OnClickListener mOnDeliverSilently = v -> {
-        handleSaveImportance(
-                ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
-    };
-
-    private void handleSaveImportance(int action, int metricsSubtype) {
-        Runnable saveImportance = () -> {
-            saveImportanceAndExitReason(action);
-            if (mIsForBlockingHelper) {
-                swapContent(action, true /* animate */);
-                mMetricsLogger.write(getLogMaker()
-                        .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
-                        .setType(MetricsEvent.TYPE_ACTION)
-                        .setSubtype(metricsSubtype));
-            }
-        };
-        if (mCheckSaveListener != null) {
-            mCheckSaveListener.checkSave(saveImportance, mSbn);
-        } else {
-            saveImportance.run();
-        }
-    }
-
-    private OnClickListener mOnUndo = v -> {
-        // Reset exit counter that we'll log and record an undo event separately (not an exit event)
-        mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
-        if (mIsForBlockingHelper) {
-            logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
-            mMetricsLogger.write(getLogMaker().setCategory(
-                    MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
-                    .setType(MetricsEvent.TYPE_DISMISS)
-                    .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
-        } else {
-            // TODO: this can't happen?
-            mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
-        }
-        saveImportanceAndExitReason(ACTION_UNDO);
-        swapContent(ACTION_UNDO, true /* animate */);
-    };
-
     public NotificationInfo(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -250,30 +170,6 @@
         void onClick(View v, Intent intent);
     }
 
-    @VisibleForTesting
-    void bindNotification(
-            final PackageManager pm,
-            final INotificationManager iNotificationManager,
-            final VisualStabilityManager visualStabilityManager,
-            final String pkg,
-            final NotificationChannel notificationChannel,
-            final Set<NotificationChannel> uniqueChannelsInRow,
-            final NotificationEntry entry,
-            final CheckSaveListener checkSaveListener,
-            final OnSettingsClickListener onSettingsClick,
-            final OnAppSettingsClickListener onAppSettingsClick,
-            boolean isDeviceProvisioned,
-            boolean isNonblockable,
-            int importance,
-            boolean wasShownHighPriority)
-            throws RemoteException {
-        bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel,
-                uniqueChannelsInRow, entry, checkSaveListener, onSettingsClick,
-                onAppSettingsClick, isDeviceProvisioned, isNonblockable,
-                false /* isBlockingHelper */,
-                importance, wasShownHighPriority);
-    }
-
     public void bindNotification(
             PackageManager pm,
             INotificationManager iNotificationManager,
@@ -282,13 +178,10 @@
             NotificationChannel notificationChannel,
             Set<NotificationChannel> uniqueChannelsInRow,
             NotificationEntry entry,
-            CheckSaveListener checkSaveListener,
             OnSettingsClickListener onSettingsClick,
             OnAppSettingsClickListener onAppSettingsClick,
             boolean isDeviceProvisioned,
             boolean isNonblockable,
-            boolean isForBlockingHelper,
-            int importance,
             boolean wasShownHighPriority)
             throws RemoteException {
         mINotificationManager = iNotificationManager;
@@ -298,18 +191,15 @@
         mPackageName = pkg;
         mUniqueChannelsInRow = uniqueChannelsInRow;
         mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
-        mEntry = entry;
         mSbn = entry.getSbn();
         mPm = pm;
         mAppSettingsClickListener = onAppSettingsClick;
         mAppName = mPackageName;
-        mCheckSaveListener = checkSaveListener;
         mOnSettingsClickListener = onSettingsClick;
         mSingleNotificationChannel = notificationChannel;
         mStartingChannelImportance = mSingleNotificationChannel.getImportance();
         mWasShownHighPriority = wasShownHighPriority;
         mIsNonblockable = isNonblockable;
-        mIsForBlockingHelper = isForBlockingHelper;
         mAppUid = mSbn.getUid();
         mDelegatePkg = mSbn.getOpPkg();
         mIsDeviceProvisioned = isDeviceProvisioned;
@@ -329,36 +219,12 @@
         bindHeader();
         bindChannelDetails();
 
-        if (mIsForBlockingHelper) {
-            bindBlockingHelper();
-        } else {
-            bindInlineControls();
-        }
+        bindInlineControls();
 
         mMetricsLogger.write(notificationControlsLogMaker());
     }
 
-    private void bindBlockingHelper() {
-        findViewById(R.id.inline_controls).setVisibility(GONE);
-        findViewById(R.id.blocking_helper).setVisibility(VISIBLE);
-
-        findViewById(R.id.undo).setOnClickListener(mOnUndo);
-
-        View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications);
-        turnOffButton.setOnClickListener(getSettingsOnClickListener());
-        turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE);
-
-        TextView keepShowing = findViewById(R.id.keep_showing);
-        keepShowing.setOnClickListener(mOnKeepShowing);
-
-        View deliverSilently = findViewById(R.id.deliver_silently);
-        deliverSilently.setOnClickListener(mOnDeliverSilently);
-    }
-
     private void bindInlineControls() {
-        findViewById(R.id.inline_controls).setVisibility(VISIBLE);
-        findViewById(R.id.blocking_helper).setVisibility(GONE);
-
         if (mIsNonblockable) {
             findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
             findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
@@ -414,8 +280,8 @@
             // app is gone, just show package name and generic icon
             mPkgIcon = mPm.getDefaultActivityIcon();
         }
-        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(mPkgIcon);
-        ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
+        ((ImageView) findViewById(R.id.pkg_icon)).setImageDrawable(mPkgIcon);
+        ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
 
         // Delegate
         bindDelegate();
@@ -445,8 +311,6 @@
         if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
             final int appUidF = mAppUid;
             return ((View view) -> {
-                logBlockingHelperCounter(
-                        NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
                 mOnSettingsClickListener.onClick(view,
                         mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
                         appUidF);
@@ -487,16 +351,13 @@
 
     private void bindDelegate() {
         TextView delegateView = findViewById(R.id.delegate_name);
-        TextView dividerView = findViewById(R.id.pkg_divider);
 
         CharSequence delegatePkg = null;
         if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
             // this notification was posted by a delegate!
             delegateView.setVisibility(View.VISIBLE);
-            dividerView.setVisibility(View.VISIBLE);
         } else {
             delegateView.setVisibility(View.GONE);
-            dividerView.setVisibility(View.GONE);
         }
     }
 
@@ -512,25 +373,19 @@
             }
         }
         TextView groupNameView = findViewById(R.id.group_name);
+        View divider = findViewById(R.id.group_divider);
         if (groupName != null) {
             groupNameView.setText(groupName);
-            groupNameView.setVisibility(View.VISIBLE);
+            groupNameView.setVisibility(VISIBLE);
+            divider.setVisibility(VISIBLE);
         } else {
-            groupNameView.setVisibility(View.GONE);
-        }
-    }
-
-
-    @VisibleForTesting
-    void logBlockingHelperCounter(String counterTag) {
-        if (mIsForBlockingHelper) {
-            mMetricsLogger.count(counterTag, 1);
+            groupNameView.setVisibility(GONE);
+            divider.setVisibility(GONE);
         }
     }
 
     private void saveImportance() {
-        if (!mIsNonblockable
-                || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
+        if (!mIsNonblockable) {
             if (mChosenImportance == null) {
                 mChosenImportance = mStartingChannelImportance;
             }
@@ -621,99 +476,13 @@
                 : R.string.inline_done_button);
     }
 
-    private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
-        switch (action) {
-            case ACTION_UNDO:
-                mChosenImportance = mStartingChannelImportance;
-                break;
-            case ACTION_DELIVER_SILENTLY:
-                mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
-                mChosenImportance = mWasShownHighPriority
-                        ? IMPORTANCE_LOW : mStartingChannelImportance;
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-    }
-
-    // only used for blocking helper
-    private void swapContent(@NotificationInfoAction int action, boolean animate) {
-        if (mExpandAnimation != null) {
-            mExpandAnimation.cancel();
-        }
-
-        View blockingHelper = findViewById(R.id.blocking_helper);
-        ViewGroup confirmation = findViewById(R.id.confirmation);
-        TextView confirmationText = findViewById(R.id.confirmation_text);
-
-        saveImportanceAndExitReason(action);
-
-        switch (action) {
-            case ACTION_UNDO:
-                break;
-            case ACTION_DELIVER_SILENTLY:
-                confirmationText.setText(R.string.notification_channel_silenced);
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-
-        boolean isUndo = action == ACTION_UNDO;
-
-        blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
-        findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE);
-        findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE);
-        confirmation.setVisibility(isUndo ? GONE : VISIBLE);
-
-        if (animate) {
-            ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA,
-                    blockingHelper.getAlpha(), isUndo ? 1f : 0f);
-            promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
-            ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
-                    confirmation.getAlpha(), isUndo ? 0f : 1f);
-            confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
-
-            mExpandAnimation = new AnimatorSet();
-            mExpandAnimation.playTogether(promptAnim, confirmAnim);
-            mExpandAnimation.setDuration(150);
-            mExpandAnimation.addListener(new AnimatorListenerAdapter() {
-                boolean mCancelled = false;
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mCancelled = true;
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (!mCancelled) {
-                        blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
-                        confirmation.setVisibility(isUndo ? GONE : VISIBLE);
-                    }
-                }
-            });
-            mExpandAnimation.start();
-        }
-
-        // Since we're swapping/update the content, reset the timeout so the UI can't close
-        // immediately after the update.
-        if (mGutsContainer != null) {
-            mGutsContainer.resetFalsingCheck();
-        }
-    }
-
     @Override
     public void onFinishedClosing() {
         if (mChosenImportance != null) {
             mStartingChannelImportance = mChosenImportance;
         }
-        mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
 
-        if (mIsForBlockingHelper) {
-            bindBlockingHelper();
-        } else {
-            bindInlineControls();
-        }
+        bindInlineControls();
 
         mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE));
     }
@@ -756,13 +525,10 @@
     }
 
     /**
-     * Closes the controls and commits the updated importance values (indirectly). If this view is
-     * being used to show the blocking helper, this will immediately dismiss the blocking helper and
-     * commit the updated importance.
+     * Closes the controls and commits the updated importance values (indirectly).
      *
      * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
-     * user does not have the ability to undo the action anymore. See
-     * {@link #swapContent(boolean, boolean)} for where undo is handled.
+     * user does not have the ability to undo the action anymore.
      */
     @VisibleForTesting
     void closeControls(View v, boolean save) {
@@ -811,7 +577,6 @@
         if (save) {
             saveImportance();
         }
-        logBlockingHelperCounter(mExitReason);
         return false;
     }
 
@@ -822,7 +587,7 @@
 
     @VisibleForTesting
     public boolean isAnimating() {
-        return mExpandAnimation != null && mExpandAnimation.isRunning();
+        return false;
     }
 
     /**
@@ -901,8 +666,7 @@
     private LogMaker notificationControlsLogMaker() {
         return getLogMaker().setCategory(MetricsEvent.ACTION_NOTE_CONTROLS)
                 .setType(MetricsEvent.TYPE_OPEN)
-                .setSubtype(mIsForBlockingHelper ? MetricsEvent.BLOCKING_HELPER_DISPLAY
-                        : MetricsEvent.BLOCKING_HELPER_UNKNOWN);
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_UNKNOWN);
     }
 
     @Retention(SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java
deleted file mode 100644
index 3ea8195..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.row;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- * Custom view for the NotificationInfo confirmation views so that the confirmation text can
- * occupy the full width of the notification and push the undo button down to the next line if
- * necessary.
- *
- * @see NotificationInfo
- */
-public class NotificationUndoLayout extends FrameLayout {
-    /**
-     * View for the prompt/confirmation text to tell the user the previous action was successful.
-     */
-    private View mConfirmationTextView;
-    /** Undo button (actionable text) view. */
-    private View mUndoView;
-
-    /**
-     * Whether {@link #mConfirmationTextView} is multiline and will require the full width of the
-     * parent (which causes the {@link #mUndoView} to push down).
-     */
-    private boolean mIsMultiline = false;
-    private int mMultilineTopMargin;
-
-    public NotificationUndoLayout(Context context) {
-        this(context, null);
-    }
-
-    public NotificationUndoLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationUndoLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mConfirmationTextView = findViewById(R.id.confirmation_text);
-        mUndoView = findViewById(R.id.undo);
-
-        mMultilineTopMargin = getResources().getDimensionPixelOffset(
-                com.android.internal.R.dimen.notification_content_margin_start);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        LayoutParams confirmationLayoutParams =
-                (LayoutParams) mConfirmationTextView.getLayoutParams();
-        LayoutParams undoLayoutParams =(LayoutParams) mUndoView.getLayoutParams();
-
-        int measuredWidth = getMeasuredWidth();
-        // Ignore the left margin on the undo button - no need for additional extra space between
-        // the text and the button.
-        int requiredWidth = mConfirmationTextView.getMeasuredWidth()
-                + confirmationLayoutParams.rightMargin
-                + confirmationLayoutParams.leftMargin
-                + mUndoView.getMeasuredWidth()
-                + undoLayoutParams.rightMargin;
-        // If the measured width isn't enough to accommodate both the undo button and the text in
-        // the same line, we'll need to adjust the view to be multi-line. Otherwise, we're done.
-        if (requiredWidth > measuredWidth) {
-            mIsMultiline = true;
-
-            // Update height requirement to the text height and the button's height (along with
-            // additional spacing for the top of the text).
-            int updatedHeight = mMultilineTopMargin
-                    + mConfirmationTextView.getMeasuredHeight()
-                    + mUndoView.getMeasuredHeight()
-                    + undoLayoutParams.topMargin
-                    + undoLayoutParams.bottomMargin;
-
-            setMeasuredDimension(measuredWidth, updatedHeight);
-        } else {
-            mIsMultiline = false;
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        // If the text view and undo view don't fit on the same line, we'll need to manually lay
-        // out the content.
-        if (mIsMultiline) {
-            // Re-align parent right/bottom values. Left and top are considered to be 0.
-            int parentBottom = getMeasuredHeight();
-            int parentRight = getMeasuredWidth();
-
-            LayoutParams confirmationLayoutParams =
-                    (LayoutParams) mConfirmationTextView.getLayoutParams();
-            LayoutParams undoLayoutParams = (LayoutParams) mUndoView.getLayoutParams();
-
-            // The confirmation text occupies the full width as computed earlier. Both side margins
-            // are equivalent, so we only need to grab the left one here.
-            mConfirmationTextView.layout(
-                    confirmationLayoutParams.leftMargin,
-                    mMultilineTopMargin,
-                    confirmationLayoutParams.leftMargin + mConfirmationTextView.getMeasuredWidth(),
-                    mMultilineTopMargin + mConfirmationTextView.getMeasuredHeight());
-
-            // The undo button is aligned bottom|end with the parent in the case of multiline text.
-            int undoViewLeft = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
-                    ? undoLayoutParams.rightMargin
-                    : parentRight - mUndoView.getMeasuredWidth() - undoLayoutParams.rightMargin;
-            mUndoView.layout(
-                    undoViewLeft,
-                    parentBottom - mUndoView.getMeasuredHeight() - undoLayoutParams.bottomMargin,
-                    undoViewLeft + mUndoView.getMeasuredWidth(),
-                    parentBottom - undoLayoutParams.bottomMargin);
-        } else {
-            super.onLayout(changed, left, top, right, bottom);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 8ee2f50..42a7c6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -332,6 +332,10 @@
                 // Put it at the end of the list.
                 peopleHeaderTarget = lastNotifIndex;
             }
+            // Offset the target to account for the current position of the people header.
+            if (currentPeopleHeaderIdx != -1 && currentPeopleHeaderIdx < peopleHeaderTarget) {
+                peopleHeaderTarget--;
+            }
         }
 
         // Add headers in reverse order to preserve indices
@@ -459,6 +463,11 @@
         return mPeopleHubView;
     }
 
+    @VisibleForTesting
+    void setPeopleHubVisible(boolean visible) {
+        mPeopleHubVisible = visible;
+    }
+
     private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
         @Override
         public void onLocaleListChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index c29ec9e..cf9d43e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -26,7 +26,6 @@
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricSourceType;
 import android.os.Trace;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -34,22 +33,17 @@
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
 
-import androidx.annotation.Nullable;
-
 import com.android.internal.graphics.ColorUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -61,8 +55,7 @@
  * Manages the different states and animations of the unlock icon.
  */
 public class LockIcon extends KeyguardAffordanceView implements
-        KeyguardStateController.Callback, NotificationWakeUpCoordinator.WakeUpListener,
-        ViewTreeObserver.OnPreDrawListener, OnHeadsUpChangedListener {
+        ViewTreeObserver.OnPreDrawListener {
 
     private static final int STATE_LOCKED = 0;
     private static final int STATE_LOCK_OPEN = 1;
@@ -70,7 +63,6 @@
     private static final int STATE_BIOMETRICS_ERROR = 3;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final AccessibilityController mAccessibilityController;
-    private final DockManager mDockManager;
     private final KeyguardStateController mKeyguardStateController;
     private final KeyguardBypassController mBypassController;
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
@@ -130,43 +122,6 @@
                     update();
                 }
             };
-    private final DockManager.DockEventListener mDockEventListener =
-            new DockManager.DockEventListener() {
-                @Override
-                public void onEvent(int event) {
-                    boolean docked = event == DockManager.STATE_DOCKED
-                            || event == DockManager.STATE_DOCKED_HIDE;
-                    if (docked != mDocked) {
-                        mDocked = docked;
-                        update();
-                    }
-        }
-    };
-
-    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
-            new KeyguardUpdateMonitorCallback() {
-                @Override
-                public void onSimStateChanged(int subId, int slotId, int simState) {
-                    mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
-                    update();
-                }
-
-                @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    update();
-                }
-
-                @Override
-                public void onBiometricRunningStateChanged(boolean running,
-                        BiometricSourceType biometricSourceType) {
-                    update();
-                }
-
-                @Override
-                public void onStrongAuthStateChanged(int userId) {
-                    update();
-                }
-    };
 
     @Inject
     public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -174,7 +129,6 @@
             KeyguardBypassController bypassController,
             NotificationWakeUpCoordinator wakeUpCoordinator,
             KeyguardStateController keyguardStateController,
-            @Nullable DockManager dockManager,
             HeadsUpManagerPhone headsUpManager) {
         super(context, attrs);
         mContext = context;
@@ -183,7 +137,6 @@
         mBypassController = bypassController;
         mWakeUpCoordinator = wakeUpCoordinator;
         mKeyguardStateController = keyguardStateController;
-        mDockManager = dockManager;
         mHeadsUpManager = headsUpManager;
     }
 
@@ -191,24 +144,14 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
-        mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
-        mWakeUpCoordinator.addListener(this);
         mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
-        if (mDockManager != null) {
-            mDockManager.addListener(mDockEventListener);
-        }
         update();
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
         mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
-        mWakeUpCoordinator.removeListener(this);
-        if (mDockManager != null) {
-            mDockManager.removeListener(mDockEventListener);
-        }
     }
 
     /**
@@ -306,7 +249,7 @@
      * Update the icon visibility
      * @return true if the visibility changed
      */
-    private boolean updateIconVisibility() {
+    boolean updateIconVisibility() {
         boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
         boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
                 || mShowingLaunchAffordance;
@@ -424,16 +367,6 @@
         return -1;
     }
 
-    @Override
-    public void onFullyHiddenChanged(boolean isFullyHidden) {
-        if (mBypassController.getBypassEnabled()) {
-            boolean changed = updateIconVisibility();
-            if (changed) {
-                update();
-            }
-        }
-    }
-
     public void setBouncerShowingScrimmed(boolean bouncerShowing) {
         mBouncerShowingScrimmed = bouncerShowing;
         if (mBypassController.getBypassEnabled()) {
@@ -454,6 +387,18 @@
         updateDarkTint();
     }
 
+    void setSimLocked(boolean simLocked) {
+        mSimLocked = simLocked;
+    }
+
+    /** Set if the device is docked. */
+    public void setDocked(boolean docked) {
+        if (mDocked != docked) {
+            mDocked = docked;
+            update();
+        }
+    }
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ERROR, UNLOCK, LOCK, SCANNING})
     @interface LockAnimIndex {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 698a430..2b1a8a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -18,20 +18,29 @@
 
 import android.content.res.TypedArray;
 import android.graphics.Color;
+import android.hardware.biometrics.BiometricSourceType;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
+import java.util.Optional;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -47,6 +56,9 @@
     private final KeyguardIndicationController mKeyguardIndicationController;
     private final StatusBarStateController mStatusBarStateController;
     private final ConfigurationController mConfigurationController;
+    private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final Optional<DockManager> mDockManager;
     private LockIcon mLockIcon;
 
     private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -55,6 +67,10 @@
         public void onViewAttachedToWindow(View v) {
             mStatusBarStateController.addCallback(mSBStateListener);
             mConfigurationController.addCallback(mConfigurationListener);
+            mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
+            mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+
+            mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
 
             mConfigurationListener.onThemeChanged();
         }
@@ -63,6 +79,11 @@
         public void onViewDetachedFromWindow(View v) {
             mStatusBarStateController.removeCallback(mSBStateListener);
             mConfigurationController.removeCallback(mConfigurationListener);
+            mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
+            mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+
+
+            mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
         }
     };
 
@@ -115,6 +136,47 @@
         }
     };
 
+    private final WakeUpListener mWakeUpListener = new WakeUpListener() {
+        @Override
+        public void onFullyHiddenChanged(boolean isFullyHidden) {
+            if (mKeyguardBypassController.getBypassEnabled()) {
+                boolean changed = mLockIcon.updateIconVisibility();
+                if (changed) {
+                    mLockIcon.update();
+                }
+            }
+        }
+    };
+
+    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onSimStateChanged(int subId, int slotId, int simState) {
+                    mLockIcon.setSimLocked(mKeyguardUpdateMonitor.isSimPinSecure());
+                    mLockIcon.update();
+                }
+
+                @Override
+                public void onKeyguardVisibilityChanged(boolean showing) {
+                    mLockIcon.update();
+                }
+
+                @Override
+                public void onBiometricRunningStateChanged(boolean running,
+                        BiometricSourceType biometricSourceType) {
+                    mLockIcon.update();
+                }
+
+                @Override
+                public void onStrongAuthStateChanged(int userId) {
+                    mLockIcon.update();
+                }
+            };
+
+    private final DockManager.DockEventListener mDockEventListener =
+            event -> mLockIcon.setDocked(event == DockManager.STATE_DOCKED
+                    || event == DockManager.STATE_DOCKED_HIDE);
+
     @Inject
     public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -123,7 +185,10 @@
             AccessibilityController accessibilityController,
             KeyguardIndicationController keyguardIndicationController,
             StatusBarStateController statusBarStateController,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            @Nullable DockManager dockManager) {
         mLockscreenGestureLogger = lockscreenGestureLogger;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
@@ -132,6 +197,9 @@
         mKeyguardIndicationController = keyguardIndicationController;
         mStatusBarStateController = statusBarStateController;
         mConfigurationController = configurationController;
+        mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
+        mKeyguardBypassController = keyguardBypassController;
+        mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
 
         mKeyguardIndicationController.setLockIconController(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d2d76c7..b84208c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -23,7 +23,6 @@
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -606,7 +605,7 @@
     }
 
     private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
-        if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
+        if (subscriptions.size() == 2) {
             SubscriptionInfo info1 = subscriptions.get(0);
             SubscriptionInfo info2 = subscriptions.get(1);
             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
new file mode 100644
index 0000000..663f011
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
+import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ControlsRequestReceiverTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var packageManager: PackageManager
+    @Mock
+    private lateinit var activityManager: ActivityManager
+    @Mock
+    private lateinit var control: Control
+
+    private val componentName = ComponentName("test_pkg", "test_cls")
+    private lateinit var receiver: ControlsRequestReceiver
+    private lateinit var wrapper: MyWrapper
+    private lateinit var intent: Intent
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        mContext.setMockPackageManager(packageManager)
+        mContext.addMockSystemService(ActivityManager::class.java, activityManager)
+
+        receiver = ControlsRequestReceiver()
+
+        wrapper = MyWrapper(context)
+
+        intent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+            putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+            putExtra(ControlsProviderService.EXTRA_CONTROL, control)
+        }
+    }
+
+    @Test
+    fun testPackageVerification_nonExistentPackage() {
+        `when`(packageManager.getPackageUid(anyString(), anyInt()))
+                .thenThrow(PackageManager.NameNotFoundException::class.java)
+
+        assertFalse(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
+    }
+
+    @Test
+    fun testPackageVerification_uidNotInForeground() {
+        `when`(packageManager.getPackageUid(anyString(), anyInt())).thenReturn(12345)
+
+        `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
+
+        assertFalse(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
+    }
+
+    @Test
+    fun testPackageVerification_OK() {
+        `when`(packageManager.getPackageUid(anyString(), anyInt())).thenReturn(12345)
+
+        `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
+        `when`(activityManager.getUidImportance(12345)).thenReturn(IMPORTANCE_FOREGROUND)
+
+        assertTrue(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
+    }
+
+    @Test
+    fun testOnReceive_packageNotVerified_nameNotFound() {
+        `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
+                .thenThrow(PackageManager.NameNotFoundException::class.java)
+
+        receiver.onReceive(wrapper, intent)
+
+        assertNull(wrapper.intent)
+    }
+
+    @Test
+    fun testOnReceive_packageNotVerified_notForeground() {
+        `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
+                .thenReturn(12345)
+
+        `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
+
+        receiver.onReceive(wrapper, intent)
+
+        assertNull(wrapper.intent)
+    }
+
+    @Test
+    fun testOnReceive_OK() {
+        `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
+                .thenReturn(12345)
+
+        `when`(activityManager.getUidImportance(eq(12345))).thenReturn(IMPORTANCE_FOREGROUND)
+
+        receiver.onReceive(wrapper, intent)
+
+        wrapper.intent?.let {
+            assertEquals(ComponentName(wrapper, ControlsRequestDialog::class.java), it.component)
+
+            assertEquals(control, it.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL))
+
+            assertEquals(componentName, it.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME))
+        } ?: run { fail("Null start intent") }
+    }
+
+    class MyWrapper(context: Context) : ContextWrapper(context) {
+        var intent: Intent? = null
+
+        override fun startActivityAsUser(intent: Intent, user: UserHandle) {
+            // Always launch activity as system
+            assertTrue(user == UserHandle.SYSTEM)
+            this.intent = intent
+        }
+
+        override fun startActivity(intent: Intent) {
+            this.intent = intent
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 6c09a46..cd46110 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -26,7 +26,6 @@
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.IWindowContainer;
 import android.view.SurfaceControl;
 
 import androidx.test.filters.SmallTest;
@@ -51,7 +50,7 @@
     private PipAnimationController mPipAnimationController;
 
     @Mock
-    private IWindowContainer mWindowContainer;
+    private SurfaceControl mLeash;
 
     @Mock
     private PipAnimationController.PipAnimationCallback mPipAnimationCallback;
@@ -65,8 +64,7 @@
     @Test
     public void getAnimator_withAlpha_returnFloatAnimator() {
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        new Rect(), 0f, 1f);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), 0f, 1f);
 
         assertEquals("Expect ANIM_TYPE_ALPHA animation",
                 animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA);
@@ -75,8 +73,7 @@
     @Test
     public void getAnimator_withBounds_returnBoundsAnimator() {
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        new Rect(), new Rect());
+                .getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), new Rect());
 
         assertEquals("Expect ANIM_TYPE_BOUNDS animation",
                 animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -88,14 +85,12 @@
         final Rect endValue1 = new Rect(100, 100, 200, 200);
         final Rect endValue2 = new Rect(200, 200, 300, 300);
         final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue1);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue1);
         oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
         oldAnimator.start();
 
         final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue2);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue2);
 
         assertEquals("getAnimator with same type returns same animator",
                 oldAnimator, newAnimator);
@@ -106,13 +101,11 @@
     @Test
     public void getAnimator_scheduleFinishPip() {
         PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        new Rect(), 0f, 1f);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), 0f, 1f);
         assertTrue("scheduleFinishPip is true", animator.shouldScheduleFinishPip());
 
         animator = mPipAnimationController
-                .getAnimator(mWindowContainer, false /* scheduleFinishPip */,
-                        new Rect(), 0f, 1f);
+                .getAnimator(mLeash, false /* scheduleFinishPip */, new Rect(), 0f, 1f);
         assertFalse("scheduleFinishPip is false", animator.shouldScheduleFinishPip());
     }
 
@@ -122,8 +115,7 @@
         final Rect endValue1 = new Rect(100, 100, 200, 200);
         final Rect endValue2 = new Rect(200, 200, 300, 300);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue1);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue1);
 
         animator.updateEndValue(endValue2);
 
@@ -135,24 +127,23 @@
         final Rect startValue = new Rect(0, 0, 100, 100);
         final Rect endValue = new Rect(100, 100, 200, 200);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue);
         animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
 
         animator.setPipAnimationCallback(mPipAnimationCallback);
 
         // onAnimationStart triggers onPipAnimationStart
         animator.onAnimationStart(animator);
-        verify(mPipAnimationCallback).onPipAnimationStart(mWindowContainer, animator);
+        verify(mPipAnimationCallback).onPipAnimationStart(animator);
 
         // onAnimationCancel triggers onPipAnimationCancel
         animator.onAnimationCancel(animator);
-        verify(mPipAnimationCallback).onPipAnimationCancel(mWindowContainer, animator);
+        verify(mPipAnimationCallback).onPipAnimationCancel(animator);
 
         // onAnimationEnd triggers onPipAnimationEnd
         animator.onAnimationEnd(animator);
-        verify(mPipAnimationCallback).onPipAnimationEnd(eq(mWindowContainer),
-                any(SurfaceControl.Transaction.class), eq(animator));
+        verify(mPipAnimationCallback).onPipAnimationEnd(any(SurfaceControl.Transaction.class),
+                eq(animator));
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
index 3b00684..b12db2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
@@ -58,7 +58,7 @@
     @Before
     public void setUp() throws Exception {
         initializeMockResources();
-        mPipBoundsHandler = new PipBoundsHandler(mContext);
+        mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext));
 
         mPipBoundsHandler.onDisplayInfoChanged(mDefaultDisplayInfo);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index e4865b6..78e9b33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -20,6 +20,9 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 
+import static com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.TYPE_NON_PERSON;
+import static com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.TYPE_PERSON;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -60,8 +63,9 @@
         final NotificationEntry entry = new NotificationEntryBuilder()
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
-                .thenReturn(false);
+        when(mPeopleNotificationIdentifier
+                .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+                .thenReturn(TYPE_NON_PERSON);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -76,8 +80,9 @@
                 .setNotification(notification)
                 .setImportance(IMPORTANCE_LOW)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
-                .thenReturn(true);
+        when(mPeopleNotificationIdentifier
+                .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+                .thenReturn(TYPE_PERSON);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -92,8 +97,9 @@
         final NotificationEntry entry = new NotificationEntryBuilder()
                 .setNotification(notification)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
-                .thenReturn(false);
+        when(mPeopleNotificationIdentifier
+                .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+                .thenReturn(TYPE_NON_PERSON);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -109,8 +115,9 @@
                 .setNotification(notification)
                 .setImportance(IMPORTANCE_LOW)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
-                .thenReturn(false);
+        when(mPeopleNotificationIdentifier
+                .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+                .thenReturn(TYPE_NON_PERSON);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -126,8 +133,9 @@
                 .setNotification(notification)
                 .setImportance(IMPORTANCE_MIN)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
-                .thenReturn(false);
+        when(mPeopleNotificationIdentifier
+                .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+                .thenReturn(TYPE_NON_PERSON);
 
         // THEN it does NOT have high priority
         assertFalse(mHighPriorityProvider.isHighPriority(entry));
@@ -149,8 +157,9 @@
                 .setNotification(notification)
                 .setChannel(channel)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
-                .thenReturn(true);
+        when(mPeopleNotificationIdentifier
+                .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+                .thenReturn(TYPE_PERSON);
 
         // THEN it does NOT have high priority
         assertFalse(mHighPriorityProvider.isHighPriority(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 5a6f888..cdf0f2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -32,6 +32,8 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
@@ -166,10 +168,8 @@
                 .setOverrideGroupKey("")
                 .build()
 
-        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
-                .thenReturn(true)
-        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
-                .thenReturn(true)
+        whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+                .thenReturn(TYPE_IMPORTANT_PERSON)
 
         val bN = Notification.Builder(mContext, "test")
                 .setStyle(Notification.MessagingStyle(""))
@@ -188,10 +188,8 @@
             whenever(it.isHeadsUp).thenReturn(true)
         }
 
-        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
-                .thenReturn(false)
-        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
-                .thenReturn(false)
+        whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+                .thenReturn(TYPE_PERSON)
 
         assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test"))
     }
@@ -213,10 +211,8 @@
                 .setUser(mContext.user)
                 .setOverrideGroupKey("")
                 .build()
-        whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
-                .thenReturn(false)
-        whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
-                .thenReturn(true)
+        whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+                .thenReturn(TYPE_PERSON)
 
         val bN = Notification.Builder(mContext, "test")
                 .setStyle(Notification.MessagingStyle(""))
@@ -231,10 +227,8 @@
                 .setUser(mContext.user)
                 .setOverrideGroupKey("")
                 .build()
-        whenever(personNotificationIdentifier.isImportantPeopleNotification(b.sbn, b.ranking))
-                .thenReturn(true)
-        whenever(personNotificationIdentifier.isPeopleNotification(b.sbn, b.ranking))
-                .thenReturn(true)
+        whenever(personNotificationIdentifier.getPeopleNotificationType(b.sbn, b.ranking))
+                .thenReturn(TYPE_IMPORTANT_PERSON)
 
         assertEquals(
                 listOf(b, a),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index b1288f8..79fa436 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.notification.people
 
-import android.app.PendingIntent
-import android.content.Intent
 import android.graphics.drawable.Drawable
 import android.testing.AndroidTestingRunner
 import android.view.View
@@ -151,7 +149,7 @@
     clickRunnable: Runnable,
     userId: Int = 0
 ): PersonModel =
-        PersonModel(id, name, mock(Drawable::class.java), clickRunnable, userId)
+        PersonModel(id, userId, name, mock(Drawable::class.java), clickRunnable)
 
 private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
         PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 2c9fd2c..5d0349d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -64,6 +64,7 @@
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
 import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -76,6 +77,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -84,12 +86,11 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
 
-import java.util.concurrent.CountDownLatch;
-
 /**
  * Functional tests for notification inflation from {@link NotificationEntryManager}.
  */
 @SmallTest
+@Ignore("Flaking")
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@@ -131,7 +132,6 @@
     private NotificationEntryManager mEntryManager;
     private NotificationRowBinderImpl mRowBinder;
     private Handler mHandler;
-    private CountDownLatch mCountDownLatch;
 
     @Before
     public void setUp() {
@@ -305,7 +305,9 @@
         verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
         NotificationEntry entry = entryCaptor.getValue();
 
-        waitForInflation();
+        // Wait for inflation
+        // row inflation, system notification, remote views, contracted view
+        waitForMessages(4);
 
         // THEN the notification has its row inflated
         assertNotNull(entry.getRow());
@@ -332,7 +334,7 @@
                 NotificationEntry.class);
         verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
         NotificationEntry entry = entryCaptor.getValue();
-        waitForInflation();
+        waitForMessages(4);
 
         Mockito.reset(mEntryListener);
         Mockito.reset(mPresenter);
@@ -340,7 +342,9 @@
         // WHEN the notification is updated
         mEntryManager.updateNotification(mSbn, mRankingMap);
 
-        waitForInflation();
+        // Wait for inflation
+        // remote views, contracted view
+        waitForMessages(2);
 
         // THEN the notification has its row and inflated
         assertNotNull(entry.getRow());
@@ -353,31 +357,32 @@
         verify(mPresenter).updateNotificationViews();
     }
 
-    private void waitForInflation() {
+    /**
+     * Wait for a certain number of messages to finish before continuing, timing out if they never
+     * occur.
+     *
+     * As part of the inflation pipeline, the main thread is forced to deal with several callbacks
+     * due to the nature of the API used (generally because they're {@link android.os.AsyncTask}
+     * callbacks). In order, these are
+     *
+     * 1) Callback after row inflation. See {@link RowInflaterTask}.
+     * 2) Callback checking if row is system notification. See
+     *    {@link ExpandableNotificationRow#setEntry}
+     * 3) Callback after remote views are created. See
+     *    {@link NotificationContentInflater.AsyncInflationTask}.
+     * 4-6) Callback after each content view is inflated/rebound from remote view. See
+     *      {@link NotificationContentInflater#applyRemoteView} and {@link InflationFlag}.
+     *
+     * Depending on the test, only some of these will be necessary. For example, generally, not
+     * every content view is inflated or the row may not be inflated if one already exists.
+     *
+     * Currently, the burden is on the developer to figure these out until we have a much more
+     * test-friendly way of executing inflation logic (i.e. pass in an executor).
+     */
+    private void waitForMessages(int numMessages) {
         mHandler.postDelayed(TIMEOUT_RUNNABLE, TIMEOUT_TIME);
-        final CountDownLatch latch = new CountDownLatch(1);
-        NotificationEntryListener inflationListener = new NotificationEntryListener() {
-            @Override
-            public void onEntryInflated(NotificationEntry entry) {
-                latch.countDown();
-            }
-
-            @Override
-            public void onEntryReinflated(NotificationEntry entry) {
-                latch.countDown();
-            }
-
-            @Override
-            public void onInflationError(StatusBarNotification notification, Exception exception) {
-                latch.countDown();
-            }
-        };
-        mEntryManager.addNotificationEntryListener(inflationListener);
-        while (latch.getCount() != 0) {
-            TestableLooper.get(this).processMessages(1);
-        }
+        TestableLooper.get(this).processMessages(numMessages);
         mHandler.removeCallbacks(TIMEOUT_RUNNABLE);
-        mEntryManager.removeNotificationEntryListener(inflationListener);
     }
 
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 54c0bde..e9dca699 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -316,74 +316,9 @@
     }
 
     @Test
-    public void testInitializeNotificationInfoView_showBlockingHelper() throws Exception {
-        NotificationInfo notificationInfoView = mock(NotificationInfo.class);
-        ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(true);
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        when(row.getIsNonblockable()).thenReturn(false);
-        StatusBarNotification statusBarNotification = row.getEntry().getSbn();
-        NotificationEntry entry = row.getEntry();
-
-        mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
-        verify(notificationInfoView).bindNotification(
-                any(PackageManager.class),
-                any(INotificationManager.class),
-                eq(mVisualStabilityManager),
-                eq(statusBarNotification.getPackageName()),
-                any(NotificationChannel.class),
-                anySet(),
-                eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
-                any(NotificationInfo.OnSettingsClickListener.class),
-                any(NotificationInfo.OnAppSettingsClickListener.class),
-                eq(false),
-                eq(false),
-                eq(true) /* isForBlockingHelper */,
-                eq(0),
-                eq(false) /* wasShownHighPriority */);
-    }
-
-    @Test
-    public void testInitializeNotificationInfoView_dontShowBlockingHelper() throws Exception {
-        NotificationInfo notificationInfoView = mock(NotificationInfo.class);
-        ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(false);
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        when(row.getIsNonblockable()).thenReturn(false);
-        StatusBarNotification statusBarNotification = row.getEntry().getSbn();
-        NotificationEntry entry = row.getEntry();
-
-        mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
-        verify(notificationInfoView).bindNotification(
-                any(PackageManager.class),
-                any(INotificationManager.class),
-                eq(mVisualStabilityManager),
-                eq(statusBarNotification.getPackageName()),
-                any(NotificationChannel.class),
-                anySet(),
-                eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
-                any(NotificationInfo.OnSettingsClickListener.class),
-                any(NotificationInfo.OnAppSettingsClickListener.class),
-                eq(false),
-                eq(false),
-                eq(false) /* isForBlockingHelper */,
-                eq(0),
-                eq(false) /* wasShownHighPriority */);
-    }
-
-    @Test
     public void testInitializeNotificationInfoView_highPriority() throws Exception {
         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
         ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(true);
         final NotificationEntry entry = row.getEntry();
         modifyRanking(entry)
                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
@@ -403,13 +338,10 @@
                 any(NotificationChannel.class),
                 anySet(),
                 eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
                 eq(false),
                 eq(false),
-                eq(true) /* isForBlockingHelper */,
-                eq(IMPORTANCE_HIGH),
                 eq(true) /* wasShownHighPriority */);
     }
 
@@ -437,13 +369,10 @@
                 any(NotificationChannel.class),
                 anySet(),
                 eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
                 eq(true),
                 eq(false),
-                eq(false) /* isForBlockingHelper */,
-                eq(0),
                 eq(false) /* wasShownHighPriority */);
     }
 
@@ -469,13 +398,10 @@
                 any(NotificationChannel.class),
                 anySet(),
                 eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
                 eq(false),
                 eq(false),
-                eq(true) /* isForBlockingHelper */,
-                eq(0),
                 eq(false) /* wasShownHighPriority */);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index c62487a..98ef691 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -119,15 +119,10 @@
     @Mock
     private PackageManager mMockPackageManager;
     @Mock
-    private NotificationBlockingHelperManager mBlockingHelperManager;
-    @Mock
     private VisualStabilityManager mVisualStabilityManager;
 
     @Before
     public void setUp() throws Exception {
-        mDependency.injectTestDependency(
-                NotificationBlockingHelperManager.class,
-                mBlockingHelperManager);
         mTestableLooper = TestableLooper.get(this);
 
         mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
@@ -183,13 +178,6 @@
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
     }
 
-    // TODO: if tests are taking too long replace this with something that makes the animation
-    // finish instantly.
-    private void waitForUndoButton() {
-        PollingCheck.waitFor(1000,
-                () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
-    }
-
     @Test
     public void testBindNotification_SetsTextApplicationName() throws Exception {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -203,12 +191,10 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
-        final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
+        final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
         assertTrue(textView.getText().toString().contains("App Name"));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
     }
@@ -228,12 +214,10 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
-        final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
+        final ImageView iconView = mNotificationInfo.findViewById(R.id.pkg_icon);
         assertEquals(iconDrawable, iconView.getDrawable());
     }
 
@@ -249,14 +233,12 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(GONE, nameView.getVisibility());
-        final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
+        final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
         assertEquals(GONE, dividerView.getVisibility());
     }
 
@@ -281,16 +263,12 @@
                 entry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(VISIBLE, nameView.getVisibility());
         assertTrue(nameView.getText().toString().contains("Proxied"));
-        final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
-        assertEquals(VISIBLE, dividerView.getVisibility());
     }
 
     @Test
@@ -305,13 +283,13 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(GONE, groupNameView.getVisibility());
+        final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
+        assertEquals(GONE, dividerView.getVisibility());
     }
 
     @Test
@@ -332,14 +310,14 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(View.VISIBLE, groupNameView.getVisibility());
         assertEquals("Test Group Name", groupNameView.getText());
+        final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
+        assertEquals(View.VISIBLE, dividerView.getVisibility());
     }
 
     @Test
@@ -354,10 +332,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(TEST_CHANNEL_NAME, textView.getText());
@@ -375,10 +351,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(GONE, textView.getVisibility());
@@ -387,7 +361,7 @@
     @Test
     public void testBindNotification_DefaultChannelUsesChannelNameIfMoreChannelsExist()
             throws Exception {
-        // Package has one channel by default.
+        // Package has more than one channel by default.
         when(mMockINotificationManager.getNumNotificationChannelsForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
         mNotificationInfo.bindNotification(
@@ -400,10 +374,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(VISIBLE, textView.getVisibility());
@@ -421,42 +393,14 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 true,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(VISIBLE, textView.getVisibility());
     }
 
     @Test
-    public void testBindNotification_BlockLink_BlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                mock(NotificationInfo.OnSettingsClickListener.class),
-                null,
-                true,
-                false,
-                true /* isBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-        final View block =
-                mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications);
-        final View interruptivenessSettings = mNotificationInfo.findViewById(
-                R.id.inline_controls);
-        assertEquals(VISIBLE, block.getVisibility());
-        assertEquals(GONE, interruptivenessSettings.getVisibility());
-    }
-
-    @Test
     public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
@@ -467,7 +411,6 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
                     latch.countDown();
@@ -475,7 +418,6 @@
                 null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
@@ -496,10 +438,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -516,14 +456,12 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
                 },
                 null,
                 false,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -541,10 +479,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         mNotificationInfo.bindNotification(
                 mMockPackageManager,
@@ -554,89 +490,16 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> { },
                 null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertEquals(View.VISIBLE, settingsButton.getVisibility());
     }
 
     @Test
-    public void testBindNotificationLogging_notBlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                true,
-                false,
-                IMPORTANCE_DEFAULT,
-                true);
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-                        && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_UNKNOWN
-        ));
-    }
-
-    @Test
-    public void testBindNotificationLogging_BlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                false,
-                true,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-                        && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_DISPLAY
-        ));
-    }
-
-    @Test
-    public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                false,
-                true,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-        mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
-    }
-
-    @Test
     public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
@@ -646,7 +509,6 @@
                 TEST_PACKAGE_NAME, mNotificationChannel,
                 createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(null, c);
                     latch.countDown();
@@ -654,7 +516,6 @@
                 null,
                 true,
                 true,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.info).performClick();
@@ -676,10 +537,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView channelNameView =
                 mNotificationInfo.findViewById(R.id.channel_name);
@@ -699,10 +558,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         assertEquals(GONE, mNotificationInfo.findViewById(
                 R.id.interruptiveness_settings).getVisibility());
@@ -722,10 +579,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 true,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
         assertEquals(View.VISIBLE, view.getVisibility());
@@ -747,10 +602,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected());
     }
@@ -767,10 +620,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 false);
         assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected());
     }
@@ -787,10 +638,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         mTestableLooper.processAllMessages();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -810,10 +659,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -836,10 +683,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -862,10 +707,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.handleCloseControls(true, false);
@@ -889,10 +732,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_UNSPECIFIED,
                 true);
 
         mNotificationInfo.handleCloseControls(true, false);
@@ -904,225 +745,6 @@
     }
 
     @Test
-    public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper()
-            throws Exception {
-        NotificationInfo.CheckSaveListener listener =
-                mock(NotificationInfo.CheckSaveListener.class);
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel /* notificationChannel */,
-                createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mEntry,
-                listener /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                true /* provisioned */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        NotificationGuts guts = spy(new NotificationGuts(mContext, null));
-        when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
-        doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
-        doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
-        guts.setGutsContent(mNotificationInfo);
-        mNotificationInfo.setGutsParent(guts);
-
-        mNotificationInfo.findViewById(R.id.keep_showing).performClick();
-
-        verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
-        mTestableLooper.processAllMessages();
-        verify(mMockINotificationManager, times(1))
-                .setNotificationsEnabledWithImportanceLockForPackage(
-                        anyString(), eq(TEST_UID), eq(true));
-    }
-
-    @Test
-    public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss_BlockingHelper()
-            throws Exception {
-        NotificationInfo.CheckSaveListener listener =
-                mock(NotificationInfo.CheckSaveListener.class);
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel /* notificationChannel */,
-                createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mEntry,
-                listener /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                true, IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
-
-        mTestableLooper.processAllMessages();
-        verify(listener, times(0)).checkSave(any(Runnable.class), eq(mSbn));
-    }
-
-    @Test
-    public void testCloseControls_checkSaveListenerDelaysStopNotifications_BlockingHelper()
-            throws Exception {
-        NotificationInfo.CheckSaveListener listener =
-                mock(NotificationInfo.CheckSaveListener.class);
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel /* notificationChannel */,
-                createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mEntry,
-                listener /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                true /* provisioned */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
-        mTestableLooper.processAllMessages();
-        verify(listener).checkSave(any(Runnable.class), eq(mSbn));
-    }
-
-    @Test
-    public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet /* numChannels */,
-                mEntry,
-                null /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-        NotificationGuts guts = mock(NotificationGuts.class);
-        doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
-        mNotificationInfo.setGutsParent(guts);
-
-        mNotificationInfo.closeControls(mNotificationInfo, true);
-
-        verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
-    }
-
-    @Test
-    public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
-            throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet /* numChannels */,
-                mEntry,
-                null /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                true /*provisioned */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
-        waitForUndoButton();
-        mNotificationInfo.handleCloseControls(true, false);
-
-        mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue((updated.getValue().getUserLockedFields()
-                & USER_LOCKED_IMPORTANCE) != 0);
-        assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
-    }
-
-    @Test
-    public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                true,
-                true,
-                IMPORTANCE_LOW,
-                false);
-
-        mNotificationInfo.findViewById(R.id.keep_showing).performClick();
-        mNotificationInfo.handleCloseControls(true, false);
-
-        mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
-        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
-    }
-
-    @Test
-    public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                true,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.handleCloseControls(true, false);
-
-        mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
-        assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
-    }
-
-    @Test
     public void testSilenceCallsUpdateNotificationChannel() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(
@@ -1135,10 +757,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1168,10 +788,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1202,10 +820,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_UNSPECIFIED,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1236,10 +852,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_MIN,
                 false);
 
         assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1273,10 +887,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_MIN,
                 false);
 
         assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1309,10 +921,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1336,10 +946,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1366,10 +974,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1399,10 +1005,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1425,14 +1029,10 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                (Runnable saveImportance, StatusBarNotification sbn) -> {
-                    saveImportance.run();
-                },
                 null,
                 null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false
         );
 
@@ -1460,14 +1060,10 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                (Runnable saveImportance, StatusBarNotification sbn) -> {
-                    saveImportance.run();
-                },
                 null,
                 null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false
         );
 
@@ -1488,14 +1084,10 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                (Runnable saveImportance, StatusBarNotification sbn) -> {
-                    saveImportance.run();
-                },
                 null,
                 null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false
         );
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index c64dd09..a263a72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -315,6 +315,24 @@
         verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
     }
 
+    @Test
+    public void testPeopleFiltering_keepPeopleHeaderWhenSectionEmpty() {
+        mSectionsManager.setPeopleHubVisible(true);
+        enablePeopleFiltering();
+
+        setStackState(
+                ChildType.PEOPLE_HEADER,
+                ChildType.ALERTING_HEADER,
+                ChildType.ALERTING,
+                ChildType.GENTLE_HEADER,
+                ChildType.GENTLE
+        );
+        mSectionsManager.updateSectionBoundaries();
+
+        verify(mNssl, never()).removeView(mSectionsManager.getPeopleHeaderView());
+        verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
+    }
+
     private void enablePeopleFiltering() {
         when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
         when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 05f10e3..487885a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -29,8 +29,10 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
@@ -63,6 +65,13 @@
     private StatusBarStateController mStatusBarStateController;
     @Mock
     private ConfigurationController mConfigurationController;
+    @Mock
+    private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private DockManager mDockManager;
+
 
     @Before
     public void setUp() {
@@ -71,7 +80,8 @@
         mLockIconController = new LockscreenLockIconController(
                 mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
                 mShadeController, mAccessibilityController, mKeyguardIndicationController,
-                mStatusBarStateController, mConfigurationController);
+                mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
+                mKeyguardBypassController, mDockManager);
 
         mLockIconController.attach(mLockIcon);
     }
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 41207c9..318a030 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -21,6 +21,7 @@
 import android.gsi.AvbPublicKey;
 import android.gsi.GsiProgress;
 import android.gsi.IGsiService;
+import android.gsi.IGsiServiceCallback;
 import android.gsi.IGsid;
 import android.os.Environment;
 import android.os.IBinder;
@@ -115,6 +116,20 @@
         }
     }
 
+    class GsiServiceCallback extends IGsiServiceCallback.Stub {
+        // 0 for success
+        private int mResult = -1;
+
+        public synchronized void onResult(int result) {
+            mResult = result;
+            notify();
+        }
+
+        public int getResult() {
+            return mResult;
+        }
+    }
+
     @Override
     public boolean startInstallation(String dsuSlot) throws RemoteException {
         IGsiService service = getGsiService();
@@ -186,7 +201,9 @@
 
     @Override
     public boolean isInstalled() throws RemoteException {
-        return getGsiService().isGsiInstalled();
+        boolean installed = SystemProperties.getBoolean("gsid.image_installed", false);
+        Slog.i(TAG, "isInstalled(): " + installed);
+        return installed;
     }
 
     @Override
@@ -196,16 +213,37 @@
 
     @Override
     public boolean remove() throws RemoteException {
-        IGsiService gsiService = getGsiService();
-        String install_dir = gsiService.getInstalledGsiImageDir();
-        return getGsiService().removeGsi();
+        try {
+            GsiServiceCallback callback = new GsiServiceCallback();
+            synchronized (callback) {
+                getGsiService().removeGsiAsync(callback);
+                callback.wait(GSID_ROUGH_TIMEOUT_MS);
+            }
+            return callback.getResult() == 0;
+        } catch (InterruptedException e) {
+            Slog.e(TAG, "remove() was interrupted");
+            return false;
+        }
     }
 
     @Override
     public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
         IGsiService gsiService = getGsiService();
         if (enable) {
-            return gsiService.enableGsi(oneShot, mDsuSlot) == 0;
+            try {
+                if (mDsuSlot == null) {
+                    mDsuSlot = gsiService.getActiveDsuSlot();
+                }
+                GsiServiceCallback callback = new GsiServiceCallback();
+                synchronized (callback) {
+                    gsiService.enableGsiAsync(oneShot, mDsuSlot, callback);
+                    callback.wait(GSID_ROUGH_TIMEOUT_MS);
+                }
+                return callback.getResult() == 0;
+            } catch (InterruptedException e) {
+                Slog.e(TAG, "setEnable() was interrupted");
+                return false;
+            }
         } else {
             return gsiService.disableGsi();
         }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 88b517c..7c833fa 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -467,9 +467,9 @@
             mNightMode = Secure.getIntForUser(context.getContentResolver(),
                     Secure.UI_NIGHT_MODE, defaultNightMode, userId);
             mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
-                    Secure.UI_NIGHT_MODE_OVERRIDE_ON, defaultNightMode, userId) != 0;
+                    Secure.UI_NIGHT_MODE_OVERRIDE_ON, 0, userId) != 0;
             mOverrideNightModeOff = Secure.getIntForUser(context.getContentResolver(),
-                    Secure.UI_NIGHT_MODE_OVERRIDE_OFF, defaultNightMode, userId) != 0;
+                    Secure.UI_NIGHT_MODE_OVERRIDE_OFF, 0, userId) != 0;
             mCustomAutoNightModeStartMilliseconds = LocalTime.ofNanoOfDay(
                     Secure.getLongForUser(context.getContentResolver(),
                     Secure.DARK_THEME_CUSTOM_START_TIME,
@@ -1045,7 +1045,6 @@
                 final TwilightState lastState = mTwilightManager.getLastTwilightState();
                 activateNightMode = lastState == null ? mComputedNightMode : lastState.isNight();
             }
-            
             updateComputedNightModeLocked(activateNightMode);
         } else {
             if (mTwilightManager != null) {
@@ -1375,6 +1374,9 @@
 
     private void updateComputedNightModeLocked(boolean activate) {
         mComputedNightMode = activate;
+        if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) {
+            return;
+        }
         if (mOverrideNightModeOn && !mComputedNightMode) {
             mComputedNightMode = true;
             return;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 93b16f7..0561567 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -110,6 +110,7 @@
             "android.hardware.audio@5.0::IDevicesFactory",
             "android.hardware.audio@6.0::IDevicesFactory",
             "android.hardware.biometrics.face@1.0::IBiometricsFace",
+            "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
             "android.hardware.bluetooth@1.0::IBluetoothHci",
             "android.hardware.camera.provider@2.4::ICameraProvider",
             "android.hardware.gnss@1.0::IGnss",
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 8fbe923..6b917bc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -19,16 +19,12 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
 
 import android.app.ActivityThread;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.OnPropertiesChangedListener;
 import android.provider.DeviceConfig.Properties;
@@ -37,7 +33,6 @@
 import android.util.ArraySet;
 import android.util.KeyValueListParser;
 import android.util.Slog;
-import android.util.SparseArray;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -294,12 +289,6 @@
     // started, the restriction is on while-in-use permissions.)
     volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;
 
-    /**
-     * UserId to Assistant ComponentName mapping.
-     * Per user Assistant ComponentName is from {@link android.provider.Settings.Secure#ASSISTANT}
-     */
-    SparseArray<ComponentName> mAssistants = new SparseArray<>();
-
     private final ActivityManagerService mService;
     private ContentResolver mResolver;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -375,8 +364,6 @@
                 Settings.Global.getUriFor(
                         Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED);
 
-    private static final Uri ASSISTANT_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
-
     private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
             Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
 
@@ -443,8 +430,6 @@
         mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
         mResolver.registerContentObserver(FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI,
                 false, this);
-        mResolver.registerContentObserver(ASSISTANT_URI, false, this,
-                UserHandle.USER_ALL);
         if (mSystemServerAutomaticHeapDumpEnabled) {
             mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
                     false, this);
@@ -460,7 +445,6 @@
         // The following read from Settings.
         updateActivityStartsLoggingEnabled();
         updateForegroundServiceStartsLoggingEnabled();
-        updateAssistant();
     }
 
     private void loadDeviceConfigConstants() {
@@ -492,8 +476,6 @@
             updateForegroundServiceStartsLoggingEnabled();
         } else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
             updateEnableAutomaticSystemServerHeapDumps();
-        } else if (ASSISTANT_URI.equals(uri)) {
-            updateAssistant();
         }
     }
 
@@ -590,32 +572,6 @@
         mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver,
                 Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1;
     }
-
-    private void updateAssistant() {
-        final List<UserInfo> users =
-                mService.mContext.getSystemService(UserManager.class).getUsers();
-        SparseArray<ComponentName> componentNames = new SparseArray<>();
-        for (int i = 0; i < users.size(); i++) {
-            final int userId = users.get(i).id;
-            final String str = Settings.Secure.getStringForUser(mResolver,
-                    Settings.Secure.ASSISTANT, userId);
-            if (!TextUtils.isEmpty(str)) {
-                componentNames.put(userId, ComponentName.unflattenFromString(str));
-            }
-        }
-        synchronized (mService) {
-            for (int i = 0; i < mAssistants.size(); i++) {
-                mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.remove(
-                        mAssistants.valueAt(i).getPackageName());
-            }
-            mAssistants = componentNames;
-            for (int i = 0; i < mAssistants.size(); i++) {
-                mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.add(
-                        mAssistants.valueAt(i).getPackageName());
-            }
-        }
-    }
-
     private void updateBackgroundFgsStartsRestriction() {
         mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fbcb010..9058ac4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -81,6 +81,8 @@
 import static android.os.Process.sendSignal;
 import static android.os.Process.setThreadPriority;
 import static android.os.Process.setThreadScheduler;
+import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
+import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
@@ -4243,7 +4245,8 @@
                 }
                 synchronized (this) {
                     mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId,
-                            ProcessList.SERVICE_ADJ, "kill background");
+                            ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED,
+                            ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background");
                 }
             }
         } finally {
@@ -4269,7 +4272,10 @@
                 // because this method is also used to simulate low memory.
                 mAllowLowerMemLevel = true;
                 mProcessList.killPackageProcessesLocked(null /* packageName */, -1 /* appId */,
-                        UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ, "kill all background");
+                        UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ,
+                        ApplicationExitInfo.REASON_USER_REQUESTED,
+                        ApplicationExitInfo.SUBREASON_UNKNOWN,
+                        "kill all background");
 
                 doLowMemReportIfNeededLocked(null);
             }
@@ -4757,6 +4763,9 @@
         boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
                 ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit,
                 evenPersistent, true /* setRemoved */,
+                packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED
+                        : ApplicationExitInfo.REASON_USER_REQUESTED,
+                ApplicationExitInfo.SUBREASON_UNKNOWN,
                 packageName == null ? ("stop user " + userId) : ("stop " + packageName));
 
         didSomething |=
@@ -4820,7 +4829,10 @@
     @GuardedBy("this")
     private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
         cleanupAppInLaunchingProvidersLocked(app, true);
-        mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
+        mProcessList.removeProcessLocked(app, false, true,
+                ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
+                ApplicationExitInfo.SUBREASON_UNKNOWN,
+                "timeout publishing content providers");
     }
 
     @GuardedBy("this")
@@ -4925,7 +4937,7 @@
             if (pid > 0 && pid != MY_PID) {
                 killProcessQuiet(pid);
                 //TODO: killProcessGroup(app.info.uid, pid);
-                mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
+                mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
                         ApplicationExitInfo.SUBREASON_UNKNOWN, "attach failed");
             } else {
                 try {
@@ -9054,7 +9066,8 @@
                 }
                 int adj = proc.setAdj;
                 if (adj >= worstType && !proc.killedByAm) {
-                    proc.kill(reason, ApplicationExitInfo.REASON_OTHER, true);
+                    proc.kill(reason, ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.SUBREASON_KILL_PID, true);
                     killed = true;
                 }
             }
@@ -9068,10 +9081,17 @@
         synchronized (this) {
             final long identity = Binder.clearCallingIdentity();
             try {
+                boolean permissionChange = KILL_APP_REASON_PERMISSIONS_REVOKED.equals(reason)
+                        || KILL_APP_REASON_GIDS_CHANGED.equals(reason);
                 mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId,
                         ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */,
                         true /* callerWillRestart */, true /* doit */, true /* evenPersistent */,
-                        false /* setRemoved */, reason != null ? reason : "kill uid");
+                        false /* setRemoved */,
+                        permissionChange ? ApplicationExitInfo.REASON_PERMISSION_CHANGE
+                        : ApplicationExitInfo.REASON_OTHER,
+                        permissionChange ? ApplicationExitInfo.SUBREASON_UNKNOWN
+                        : ApplicationExitInfo.SUBREASON_KILL_UID,
+                        reason != null ? reason : "kill uid");
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -9396,7 +9416,10 @@
                 for (int i=procsToKill.size()-1; i>=0; i--) {
                     ProcessRecord proc = procsToKill.get(i);
                     Slog.i(TAG, "Removing system update proc: " + proc);
-                    mProcessList.removeProcessLocked(proc, true, false, "system update done");
+                    mProcessList.removeProcessLocked(proc, true, false,
+                            ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.SUBREASON_SYSTEM_UPDATE_DONE,
+                            "system update done");
                 }
             }
 
@@ -14400,7 +14423,8 @@
                             + cpr.name.flattenToShortString()
                             + " in dying proc " + (proc != null ? proc.processName : "??")
                             + " (adj " + (proc != null ? proc.setAdj : "??") + ")",
-                            ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.REASON_DEPENDENCY_DIED,
+                            ApplicationExitInfo.SUBREASON_UNKNOWN,
                             true);
                 }
             } else if (capp.thread != null && conn.provider.provider != null) {
@@ -15892,7 +15916,10 @@
                                                 -1);
                                         mProcessList.killPackageProcessesLocked(ssp,
                                                 UserHandle.getAppId(extraUid),
-                                                userId, ProcessList.INVALID_ADJ, "change " + ssp);
+                                                userId, ProcessList.INVALID_ADJ,
+                                                ApplicationExitInfo.REASON_USER_REQUESTED,
+                                                ApplicationExitInfo.SUBREASON_UNKNOWN,
+                                                "change " + ssp);
                                     }
                                     cleanupDisabledPackageComponentsLocked(ssp, userId,
                                             intent.getStringArrayExtra(
@@ -18622,7 +18649,10 @@
 
                 final int N = procs.size();
                 for (int i = 0; i < N; i++) {
-                    mProcessList.removeProcessLocked(procs.get(i), false, true, "kill all fg");
+                    mProcessList.removeProcessLocked(procs.get(i), false, true,
+                            ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.SUBREASON_KILL_ALL_FG,
+                            "kill all fg");
                 }
             }
         }
@@ -18844,7 +18874,8 @@
                     final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
                     if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             && pr.curReceivers.isEmpty()) {
-                        pr.kill("remove task", ApplicationExitInfo.REASON_OTHER, true);
+                        pr.kill("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
+                                ApplicationExitInfo.SUBREASON_UNKNOWN, true);
                     } else {
                         // We delay killing processes that are not in the background or running a
                         // receiver.
@@ -18861,7 +18892,7 @@
                         true /* keepIfLarge */);
                 if (proc != null) {
                     mProcessList.removeProcessLocked(proc, false /* callerWillRestart */,
-                            true /* allowRestart */, reason);
+                            true /* allowRestart */,  ApplicationExitInfo.REASON_OTHER, reason);
                 }
             }
         }
@@ -19547,7 +19578,10 @@
         try {
             synchronized(this) {
                 mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid),
-                        userId, ProcessList.FOREGROUND_APP_ADJ, "dep: " + packageName);
+                        userId, ProcessList.FOREGROUND_APP_ADJ,
+                        ApplicationExitInfo.REASON_DEPENDENCY_DIED,
+                        ApplicationExitInfo.SUBREASON_UNKNOWN,
+                        "dep: " + packageName);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 789f719..b1fc029 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -395,7 +395,7 @@
                     () -> {
                         synchronized (mService) {
                             killAppImmediateLocked(p, ApplicationExitInfo.REASON_OTHER,
-                                    ApplicationExitInfo.SUBREASON_UNKNOWN,
+                                    ApplicationExitInfo.SUBREASON_INVALID_STATE,
                                     "forced", "killed for invalid state");
                         }
                     },
@@ -510,8 +510,8 @@
                 stopReportingCrashesLocked(r);
             }
             if (res == AppErrorDialog.RESTART) {
-                mService.mProcessList.removeProcessLocked(r, false, true, "crash",
-                        ApplicationExitInfo.REASON_CRASH);
+                mService.mProcessList.removeProcessLocked(r, false, true,
+                        ApplicationExitInfo.REASON_CRASH, "crash");
                 if (taskId != INVALID_TASK_ID) {
                     try {
                         mService.startActivityFromRecents(taskId,
@@ -529,8 +529,8 @@
                     // Kill it with fire!
                     mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
                     if (!r.isPersistent()) {
-                        mService.mProcessList.removeProcessLocked(r, false, false, "crash",
-                                ApplicationExitInfo.REASON_CRASH);
+                        mService.mProcessList.removeProcessLocked(r, false, false,
+                                ApplicationExitInfo.REASON_CRASH, "crash");
                         mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
                     }
                 } finally {
@@ -747,8 +747,8 @@
                 // Don't let services in this process be restarted and potentially
                 // annoy the user repeatedly.  Unless it is persistent, since those
                 // processes run critical code.
-                mService.mProcessList.removeProcessLocked(app, false, tryAgain, "crash",
-                        ApplicationExitInfo.REASON_CRASH);
+                mService.mProcessList.removeProcessLocked(app, false, tryAgain,
+                        ApplicationExitInfo.REASON_CRASH, "crash");
                 mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
                 if (!showBackground) {
                     return false;
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index cba6b92..a09aa64 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -348,6 +348,7 @@
         } else {
             // always override the existing info since we are now more informational.
             info.setReason(raw.getReason());
+            info.setSubReason(raw.getSubReason());
             info.setStatus(0);
             info.setTimestamp(System.currentTimeMillis());
             info.setDescription(raw.getDescription());
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index e7b467a..aa37b4a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -840,7 +840,8 @@
                     // definition not re-use the same process again, and it is
                     // good to avoid having whatever code was running in them
                     // left sitting around after no longer needed.
-                    app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER, true);
+                    app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);
                 } else {
                     // Keeping this process, update its uid.
                     updateAppUidRecLocked(app);
@@ -2166,7 +2167,8 @@
             }
             if (app.waitingToKill != null && app.curReceivers.isEmpty()
                     && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
-                app.kill(app.waitingToKill, ApplicationExitInfo.REASON_OTHER, true);
+                app.kill(app.waitingToKill, ApplicationExitInfo.REASON_USER_REQUESTED,
+                        ApplicationExitInfo.SUBREASON_UNKNOWN, true);
                 success = false;
             } else {
                 int processGroup;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3a5447e..a9d18e0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2378,7 +2378,7 @@
             killProcessQuiet(pid);
             Process.killProcessGroup(app.uid, app.pid);
             noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
-                    ApplicationExitInfo.SUBREASON_UNKNOWN, reason);
+                    ApplicationExitInfo.SUBREASON_INVALID_START, reason);
             return false;
         }
         mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
@@ -2463,7 +2463,7 @@
                         killProcessQuiet(app.pid);
                         ProcessList.killProcessGroup(app.uid, app.pid);
                         noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
-                                ApplicationExitInfo.SUBREASON_UNKNOWN, "hasn't been killed");
+                                ApplicationExitInfo.SUBREASON_REMOVE_LRU, "hasn't been killed");
                     } else {
                         app.pendingStart = false;
                     }
@@ -2481,10 +2481,11 @@
 
     @GuardedBy("mService")
     boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj,
-            String reason) {
+            int reasonCode, int subReason, String reason) {
         return killPackageProcessesLocked(packageName, appId, userId, minOomAdj,
                 false /* callerWillRestart */, true /* allowRestart */, true /* doit */,
-                false /* evenPersistent */, false /* setRemoved */, reason);
+                false /* evenPersistent */, false /* setRemoved */, reasonCode,
+                subReason, reason);
     }
 
     @GuardedBy("mService")
@@ -2517,7 +2518,8 @@
     @GuardedBy("mService")
     final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
-            boolean doit, boolean evenPersistent, boolean setRemoved, String reason) {
+            boolean doit, boolean evenPersistent, boolean setRemoved, int reasonCode,
+            int subReason, String reason) {
         ArrayList<ProcessRecord> procs = new ArrayList<>();
 
         // Remove all processes this package may have touched: all with the
@@ -2589,7 +2591,8 @@
 
         int N = procs.size();
         for (int i=0; i<N; i++) {
-            removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
+            removeProcessLocked(procs.get(i), callerWillRestart, allowRestart,
+                    reasonCode, subReason, reason);
         }
         killAppZygotesLocked(packageName, appId, userId, false /* force */);
         mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
@@ -2598,13 +2601,14 @@
 
     @GuardedBy("mService")
     boolean removeProcessLocked(ProcessRecord app,
-            boolean callerWillRestart, boolean allowRestart, String reason) {
-        return removeProcessLocked(app, callerWillRestart, allowRestart, reason,
-                ApplicationExitInfo.REASON_OTHER);
+            boolean callerWillRestart, boolean allowRestart, int reasonCode, String reason) {
+        return removeProcessLocked(app, callerWillRestart, allowRestart, reasonCode,
+                ApplicationExitInfo.SUBREASON_UNKNOWN, reason);
     }
 
-    boolean removeProcessLocked(ProcessRecord app,
-            boolean callerWillRestart, boolean allowRestart, String reason, int reasonCode) {
+    @GuardedBy("mService")
+    boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart,
+            boolean allowRestart, int reasonCode, int subReason, String reason) {
         final String name = app.processName;
         final int uid = app.uid;
         if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
@@ -2640,7 +2644,7 @@
                     needRestart = true;
                 }
             }
-            app.kill(reason, reasonCode, true);
+            app.kill(reason, reasonCode, subReason, true);
             mService.handleAppDiedLocked(app, willRestart, allowRestart);
             if (willRestart) {
                 removeLruProcessLocked(app);
@@ -2838,7 +2842,8 @@
 
         final int N = procs.size();
         for (int i = 0; i < N; i++) {
-            removeProcessLocked(procs.get(i), false, true, "kill all background except");
+            removeProcessLocked(procs.get(i), false, true, ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.SUBREASON_KILL_ALL_BG_EXCEPT, "kill all background except");
         }
     }
 
@@ -4004,7 +4009,8 @@
                 return false;
             }
 
-            app.kill(reason, ApplicationExitInfo.REASON_OTHER, true);
+            app.kill(reason, ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.SUBREASON_IMPERCEPTIBLE, true);
 
             if (!app.isolated) {
                 mLastProcessKillTimes.put(app.processName, app.uid, SystemClock.uptimeMillis());
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 85f36aa..45c3aeb 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -40,6 +40,8 @@
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OpEventProxyInfo;
+import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
+import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -60,8 +62,6 @@
 import static android.content.Intent.EXTRA_REPLACING;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
 
 import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
 
@@ -5683,7 +5683,7 @@
         if (mRarelyUsedPackages.contains(packageName)) {
             mRarelyUsedPackages.remove(packageName);
             if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
-                mSamplingStrategy = RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
+                mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
                 resampleAppOpForPackageLocked(packageName);
             }
         }
@@ -5692,7 +5692,7 @@
     /** Resamples package and appop to watch from the list provided. */
     private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
         if (!packageNames.isEmpty()) {
-            mSamplingStrategy = RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
+            mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
             resampleAppOpForPackageLocked(packageNames.get(
                     ThreadLocalRandom.current().nextInt(packageNames.size())));
         }
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 8687f35..7bdeb59 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -63,7 +63,7 @@
     private Map<String, Boolean> mPackageOverrides;
 
     public CompatChange(long changeId) {
-        this(changeId, null, -1, false, null);
+        this(changeId, null, -1, false, false, null);
     }
 
     /**
@@ -74,8 +74,8 @@
      * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set.
      */
     public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
-            boolean disabled, String description) {
-        super(changeId, name, enableAfterTargetSdk, disabled, description);
+            boolean disabled, boolean loggingOnly, String description) {
+        super(changeId, name, enableAfterTargetSdk, disabled, loggingOnly, description);
     }
 
     /**
@@ -83,7 +83,7 @@
      */
     public CompatChange(Change change) {
         super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
-                change.getDisabled(), change.getDescription());
+                change.getDisabled(), change.getLoggingOnly(), change.getDescription());
     }
 
     void registerListener(ChangeListener listener) {
@@ -105,6 +105,10 @@
      * @param enabled Whether or not to enable the change.
      */
     void addPackageOverride(String pname, boolean enabled) {
+        if (getLoggingOnly()) {
+            throw new IllegalArgumentException(
+                    "Can't add overrides for a logging only change " + toString());
+        }
         if (mPackageOverrides == null) {
             mPackageOverrides = new HashMap<>();
         }
@@ -160,6 +164,9 @@
         if (getDisabled()) {
             sb.append("; disabled");
         }
+        if (getLoggingOnly()) {
+            sb.append("; loggingOnly");
+        }
         if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
             sb.append("; packageOverrides=").append(mPackageOverrides);
         }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 441d9d9..bfc2f82 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -206,6 +206,19 @@
     }
 
     /**
+     * Returns whether the change is marked as logging only.
+     */
+    boolean isLoggingOnly(long changeId) {
+        synchronized (mChanges) {
+            CompatChange c = mChanges.get(changeId);
+            if (c == null) {
+                return false;
+            }
+            return c.getLoggingOnly();
+        }
+    }
+
+    /**
      * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
      * restores the default behaviour for the given change and app, once any app processes have been
      * restarted.
@@ -365,6 +378,7 @@
                         change.getName(),
                         change.getEnableAfterTargetSdk(),
                         change.getDisabled(),
+                        change.getLoggingOnly(),
                         change.getDescription());
             }
             return changeInfos;
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index 4bf606e..9e18c74 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -20,6 +20,7 @@
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
 import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
 
 import android.content.Context;
@@ -51,12 +52,13 @@
 
     @Override
     public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
-        boolean debuggableBuild = false;
-        boolean finalBuild = false;
-        int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+        if (mCompatConfig.isLoggingOnly(changeId)) {
+            return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1);
+        }
 
-        debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
-        finalBuild = mAndroidBuildClassifier.isFinalBuild();
+        boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
+        boolean finalBuild = mAndroidBuildClassifier.isFinalBuild();
+        int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
 
         // Allow any override for userdebug or eng builds.
         if (debuggableBuild) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e484ca0..968528c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -52,7 +52,6 @@
 import android.net.IpPrefix;
 import android.net.IpSecManager;
 import android.net.IpSecManager.IpSecTunnelInterface;
-import android.net.IpSecManager.UdpEncapsulationSocket;
 import android.net.IpSecTransform;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -2201,7 +2200,6 @@
         /** Signal to ensure shutdown is honored even if a new Network is connected. */
         private boolean mIsRunning = true;
 
-        @Nullable private UdpEncapsulationSocket mEncapSocket;
         @Nullable private IpSecTunnelInterface mTunnelIface;
         @Nullable private IkeSession mSession;
         @Nullable private Network mActiveNetwork;
@@ -2352,29 +2350,21 @@
                     resetIkeState();
                     mActiveNetwork = network;
 
-                    // TODO(b/149356682): Update this based on new IKE API
-                    mEncapSocket = mIpSecManager.openUdpEncapsulationSocket();
-
-                    // TODO(b/149356682): Update this based on new IKE API
                     final IkeSessionParams ikeSessionParams =
-                            VpnIkev2Utils.buildIkeSessionParams(mProfile, mEncapSocket);
+                            VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, network);
                     final ChildSessionParams childSessionParams =
                             VpnIkev2Utils.buildChildSessionParams();
 
                     // TODO: Remove the need for adding two unused addresses with
                     // IPsec tunnels.
+                    final InetAddress address = InetAddress.getLocalHost();
                     mTunnelIface =
                             mIpSecManager.createIpSecTunnelInterface(
-                                    ikeSessionParams.getServerAddress() /* unused */,
-                                    ikeSessionParams.getServerAddress() /* unused */,
+                                    address /* unused */,
+                                    address /* unused */,
                                     network);
                     mNetd.setInterfaceUp(mTunnelIface.getInterfaceName());
 
-                    // Socket must be bound to prevent network switches from causing
-                    // the IKE teardown to fail/timeout.
-                    // TODO(b/149356682): Update this based on new IKE API
-                    network.bindSocket(mEncapSocket.getFileDescriptor());
-
                     mSession = mIkev2SessionCreator.createIkeSession(
                             mContext,
                             ikeSessionParams,
@@ -2459,16 +2449,6 @@
                 mSession.kill(); // Kill here to make sure all resources are released immediately
                 mSession = null;
             }
-
-            // TODO(b/149356682): Update this based on new IKE API
-            if (mEncapSocket != null) {
-                try {
-                    mEncapSocket.close();
-                } catch (IOException e) {
-                    Log.e(TAG, "Failed to close encap socket", e);
-                }
-                mEncapSocket = null;
-            }
         }
 
         /**
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 33fc32b..3da304c 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -35,10 +35,10 @@
 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
 
 import android.annotation.NonNull;
+import android.content.Context;
 import android.net.Ikev2VpnProfile;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
-import android.net.IpSecManager.UdpEncapsulationSocket;
 import android.net.IpSecTransform;
 import android.net.Network;
 import android.net.RouteInfo;
@@ -84,18 +84,14 @@
  */
 public class VpnIkev2Utils {
     static IkeSessionParams buildIkeSessionParams(
-            @NonNull Ikev2VpnProfile profile, @NonNull UdpEncapsulationSocket socket) {
-        // TODO(b/149356682): Update this based on new IKE API. Only numeric addresses supported
-        //                    until then. All others throw IAE (caught by caller).
-        final InetAddress serverAddr = InetAddresses.parseNumericAddress(profile.getServerAddr());
+            @NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) {
         final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
         final IkeIdentification remoteId = parseIkeIdentification(profile.getServerAddr());
 
-        // TODO(b/149356682): Update this based on new IKE API.
         final IkeSessionParams.Builder ikeOptionsBuilder =
-                new IkeSessionParams.Builder()
-                        .setServerAddress(serverAddr)
-                        .setUdpEncapsulationSocket(socket)
+                new IkeSessionParams.Builder(context)
+                        .setServerHostname(profile.getServerAddr())
+                        .setNetwork(network)
                         .setLocalIdentification(localId)
                         .setRemoteIdentification(remoteId);
         setIkeAuth(profile, ikeOptionsBuilder);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 74c1e63..61b18ee 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -83,6 +83,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * {@hide}
@@ -399,15 +400,22 @@
     public void notifyChange(Uri[] uris, IContentObserver observer,
             boolean observerWantsSelfNotifications, int flags, int userHandle,
             int targetSdkVersion, String callingPackage) {
+        final ObserverCollector collector = new ObserverCollector();
         for (Uri uri : uris) {
             notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle,
-                    targetSdkVersion, callingPackage);
+                    targetSdkVersion, callingPackage, collector);
+        }
+        final long token = clearCallingIdentity();
+        try {
+            collector.dispatch();
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     public void notifyChange(Uri uri, IContentObserver observer,
             boolean observerWantsSelfNotifications, int flags, int userHandle,
-            int targetSdkVersion, String callingPackage) {
+            int targetSdkVersion, String callingPackage, ObserverCollector collector) {
         if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
                 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
 
@@ -442,22 +450,9 @@
         // process rather than the caller's process. We will restore this before returning.
         long identityToken = clearCallingIdentity();
         try {
-            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
             synchronized (mRootNode) {
                 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
-                        flags, userHandle, calls);
-            }
-            final int numCalls = calls.size();
-            for (int i = 0; i < numCalls; i++) {
-                // Immediately dispatch notifications to foreground apps that
-                // are important to the user; all other background observers are
-                // delayed to avoid stampeding
-                final ObserverCall oc = calls.get(i);
-                if (oc.mProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-                    oc.run();
-                } else {
-                    BackgroundThread.getHandler().postDelayed(oc, BACKGROUND_OBSERVER_DELAY);
-                }
+                        flags, userHandle, collector);
             }
             if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
                 SyncManager syncManager = getSyncManager();
@@ -487,40 +482,84 @@
         }
     }
 
-    public void notifyChange(Uri uri, IContentObserver observer,
-            boolean observerWantsSelfNotifications, boolean syncToNetwork,
-            String callingPackage) {
-        notifyChange(uri, observer, observerWantsSelfNotifications,
-                syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
-                UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT, callingPackage);
-    }
-
-    /** {@hide} */
+    /**
+     * Collection of detected change notifications that should be delivered.
+     * <p>
+     * To help reduce Binder transaction overhead, this class clusters together
+     * multiple {@link Uri} where all other arguments are identical.
+     */
     @VisibleForTesting
-    public static final class ObserverCall implements Runnable {
-        final IContentObserver mObserver;
-        final boolean mSelfChange;
-        final Uri mUri;
-        final int mUserId;
-        final int mProcState;
+    public static class ObserverCollector {
+        private final ArrayMap<Key, List<Uri>> collected = new ArrayMap<>();
 
-        ObserverCall(IContentObserver observer, boolean selfChange, Uri uri, int userId,
-                int procState) {
-            mObserver = observer;
-            mSelfChange = selfChange;
-            mUri = uri;
-            mUserId = userId;
-            mProcState = procState;
+        private static class Key {
+            final IContentObserver observer;
+            final int uid;
+            final boolean selfChange;
+            final int flags;
+            final int userId;
+
+            Key(IContentObserver observer, int uid, boolean selfChange, int flags, int userId) {
+                this.observer = observer;
+                this.uid = uid;
+                this.selfChange = selfChange;
+                this.flags = flags;
+                this.userId = userId;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (!(o instanceof Key)) {
+                    return false;
+                }
+                final Key other = (Key) o;
+                return Objects.equals(observer, other.observer)
+                        && (uid == other.uid)
+                        && (selfChange == other.selfChange)
+                        && (flags == other.flags)
+                        && (userId == other.userId);
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(observer, uid, selfChange, flags, userId);
+            }
         }
 
-        @Override
-        public void run() {
-            try {
-                mObserver.onChange(mSelfChange, mUri, mUserId);
-                if (DEBUG) Slog.d(TAG, "Notified " + mObserver + " of update at " + mUri);
-            } catch (RemoteException ignored) {
-                // We already have a death observer that will clean up if the
-                // remote process dies
+        public void collect(IContentObserver observer, int uid, boolean selfChange, Uri uri,
+                int flags, int userId) {
+            final Key key = new Key(observer, uid, selfChange, flags, userId);
+            List<Uri> value = collected.get(key);
+            if (value == null) {
+                value = new ArrayList<>();
+                collected.put(key, value);
+            }
+            value.add(uri);
+        }
+
+        public void dispatch() {
+            for (int i = 0; i < collected.size(); i++) {
+                final Key key = collected.keyAt(i);
+                final List<Uri> value = collected.valueAt(i);
+
+                final Runnable task = () -> {
+                    try {
+                        key.observer.onChangeEtc(key.selfChange,
+                                value.toArray(new Uri[value.size()]), key.flags, key.userId);
+                    } catch (RemoteException ignored) {
+                    }
+                };
+
+                // Immediately dispatch notifications to foreground apps that
+                // are important to the user; all other background observers are
+                // delayed to avoid stampeding
+                final int procState = LocalServices.getService(ActivityManagerInternal.class)
+                        .getUidProcessState(key.uid);
+                if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                    task.run();
+                } else {
+                    BackgroundThread.getHandler().postDelayed(task, BACKGROUND_OBSERVER_DELAY);
+                }
             }
         }
     }
@@ -1455,10 +1494,6 @@
             }
         }
 
-        public static final int INSERT_TYPE = 0;
-        public static final int UPDATE_TYPE = 1;
-        public static final int DELETE_TYPE = 2;
-
         private String mName;
         private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
         private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
@@ -1588,7 +1623,7 @@
 
         private void collectMyObserversLocked(Uri uri, boolean leaf, IContentObserver observer,
                                               boolean observerWantsSelfNotifications, int flags,
-                                              int targetUserHandle, ArrayList<ObserverCall> calls) {
+                                              int targetUserHandle, ObserverCollector collector) {
             int N = mObservers.size();
             IBinder observerBinder = observer == null ? null : observer.asBinder();
             for (int i = 0; i < N; i++) {
@@ -1628,10 +1663,8 @@
                     if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
                             + " flags=" + Integer.toHexString(flags)
                             + " desc=" + entry.notifyForDescendants);
-                    final int procState = LocalServices.getService(ActivityManagerInternal.class)
-                            .getUidProcessState(entry.uid);
-                    calls.add(new ObserverCall(entry.observer, selfChange, uri,
-                            targetUserHandle, procState));
+                    collector.collect(entry.observer, entry.uid, selfChange, uri, flags,
+                            targetUserHandle);
                 }
             }
         }
@@ -1641,21 +1674,21 @@
          */
         public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
                                            boolean observerWantsSelfNotifications, int flags,
-                                           int targetUserHandle, ArrayList<ObserverCall> calls) {
+                                           int targetUserHandle, ObserverCollector collector) {
             String segment = null;
             int segmentCount = countUriSegments(uri);
             if (index >= segmentCount) {
                 // This is the leaf node, notify all observers
                 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
                 collectMyObserversLocked(uri, true, observer, observerWantsSelfNotifications,
-                        flags, targetUserHandle, calls);
+                        flags, targetUserHandle, collector);
             } else if (index < segmentCount){
                 segment = getUriSegment(uri, index);
                 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
                         + segment);
                 // Notify any observers at this level who are interested in descendants
                 collectMyObserversLocked(uri, false, observer, observerWantsSelfNotifications,
-                        flags, targetUserHandle, calls);
+                        flags, targetUserHandle, collector);
             }
 
             int N = mChildren.size();
@@ -1664,7 +1697,7 @@
                 if (segment == null || node.mName.equals(segment)) {
                     // We found the child,
                     node.collectObserversLocked(uri, index + 1, observer,
-                            observerWantsSelfNotifications, flags, targetUserHandle, calls);
+                            observerWantsSelfNotifications, flags, targetUserHandle, collector);
                     if (segment != null) {
                         break;
                     }
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8c510b7..e9c4b51 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -472,8 +472,7 @@
 
     private int mSyncRandomOffset;
 
-    // STOPSHIP: b/143656271 this should be true on launch
-    private static final boolean DELETE_LEGACY_PARCEL_FILES = false;
+    private static final boolean DELETE_LEGACY_PARCEL_FILES = true;
     private static final String LEGACY_STATUS_FILE_NAME = "status.bin";
     private static final String LEGACY_STATISTICS_FILE_NAME = "stats.bin";
 
@@ -2076,7 +2075,7 @@
         }
 
         // if upgrade to proto was successful, delete parcel file
-        if (DELETE_LEGACY_PARCEL_FILES && mStatusFile.exists()) {
+        if (DELETE_LEGACY_PARCEL_FILES && parcelStatus.exists() && mStatusFile.exists()) {
             parcelStatus.delete();
         }
     }
@@ -2475,7 +2474,7 @@
         }
 
         // if upgrade to proto was successful, delete parcel file
-        if (DELETE_LEGACY_PARCEL_FILES && mStatisticsFile.exists()) {
+        if (DELETE_LEGACY_PARCEL_FILES && parcelStats.exists() && mStatisticsFile.exists()) {
             parcelStats.delete();
         }
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 571f582..1869a46 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2480,6 +2480,11 @@
     void onSessionCreated(IInputMethod method, IInputMethodSession session,
             InputChannel channel) {
         synchronized (mMethodMap) {
+            if (mUserSwitchHandlerTask != null) {
+                // We have a pending user-switching task so it's better to just ignore this session.
+                channel.dispose();
+                return;
+            }
             if (mCurMethod != null && method != null
                     && mCurMethod.asBinder() == method.asBinder()) {
                 if (mCurClient != null) {
diff --git a/services/core/java/com/android/server/integrity/TEST_MAPPING b/services/core/java/com/android/server/integrity/TEST_MAPPING
index ca7f396..4959204 100644
--- a/services/core/java/com/android/server/integrity/TEST_MAPPING
+++ b/services/core/java/com/android/server/integrity/TEST_MAPPING
@@ -7,6 +7,14 @@
           "include-filter": "com.android.server.integrity."
         }
       ]
+    },
+    {
+      "name": "GtsSecurityHostTestCases",
+      "options": [
+        {
+          "include-filter": "com.google.android.security.gts.AppIntegrityManagerTest"
+        }
+      ]
     }
   ]
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 6faf674..c1c3760 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1572,6 +1572,24 @@
                     "This operation requires secure lock screen feature");
         }
         checkWritePermission(userId);
+
+        // When changing credential for profiles with unified challenge, some callers
+        // will pass in empty credential while others will pass in the credential of
+        // the parent user. setLockCredentialInternal() handles the formal case (empty
+        // credential) correctly but not the latter. As a stopgap fix, convert the latter
+        // case to the formal. The long-term fix would be fixing LSS such that it should
+        // accept only the parent user credential on its public API interfaces, swap it
+        // with the profile's random credential at that API boundary (i.e. here) and make
+        // sure LSS internally does not special case profile with unififed challenge: b/80170828.
+        if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
+            // Verify the parent credential again, to make sure we have a fresh enough
+            // auth token such that getDecryptedPasswordForTiedProfile() inside
+            // setLockCredentialInternal() can function correctly.
+            verifyCredential(savedCredential, /* challenge */ 0,
+                    mUserManager.getProfileParent(userId).id);
+            savedCredential.zeroize();
+            savedCredential = LockscreenCredential.createNone();
+        }
         synchronized (mSeparateChallengeLock) {
             if (!setLockCredentialInternal(credential, savedCredential,
                     userId, /* isLockTiedToParent= */ false)) {
@@ -1627,6 +1645,7 @@
             // get credential from keystore when managed profile has unified lock
             if (savedCredential.isNone()) {
                 try {
+                    //TODO: remove as part of b/80170828
                     savedCredential = getDecryptedPasswordForTiedProfile(userId);
                 } catch (FileNotFoundException e) {
                     Slog.i(TAG, "Child profile key not found");
@@ -2876,6 +2895,7 @@
         if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
             // get credential from keystore when managed profile has unified lock
             try {
+                //TODO: remove as part of b/80170828
                 savedCredential = getDecryptedPasswordForTiedProfile(userId);
             } catch (FileNotFoundException e) {
                 Slog.i(TAG, "Child profile key not found");
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f144405..4cb1ed9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -111,7 +111,6 @@
         void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
         void onSessionCreated(@NonNull MediaRoute2Provider provider,
                 @Nullable RoutingSessionInfo sessionInfo, long requestId);
-        void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId);
         void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo);
         void onSessionReleased(@NonNull MediaRoute2Provider provider,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index e64776c..36a7bd9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -328,19 +328,6 @@
         mCallback.onSessionCreated(this, sessionInfo, requestId);
     }
 
-    private void onSessionCreationFailed(Connection connection, long requestId) {
-        if (mActiveConnection != connection) {
-            return;
-        }
-
-        if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
-            Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_NONE");
-            return;
-        }
-
-        mCallback.onSessionCreationFailed(this, requestId);
-    }
-
     private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) {
         if (mActiveConnection != connection) {
             return;
@@ -543,10 +530,6 @@
             mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, requestId));
         }
 
-        void postSessionCreationFailed(long requestId) {
-            mHandler.post(() -> onSessionCreationFailed(Connection.this, requestId));
-        }
-
         void postSessionUpdated(RoutingSessionInfo sessionInfo) {
             mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo));
         }
@@ -555,7 +538,7 @@
             mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
         }
 
-        void postSessionReleased(long requestId, int reason) {
+        void postRequestFailed(long requestId, int reason) {
             mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
         }
     }
@@ -589,14 +572,6 @@
         }
 
         @Override
-        public void notifySessionCreationFailed(long requestId) {
-            Connection connection = mConnectionRef.get();
-            if (connection != null) {
-                connection.postSessionCreationFailed(requestId);
-            }
-        }
-
-        @Override
         public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
@@ -616,7 +591,7 @@
         public void notifyRequestFailed(long requestId, int reason) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
-                connection.postSessionReleased(requestId, reason);
+                connection.postRequestFailed(requestId, reason);
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e78a35c..16f2add 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -608,7 +608,8 @@
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        routerRecord, route, uniqueRequestId, sessionHints));
+                        routerRecord, /* managerRecord= */ null, route, uniqueRequestId,
+                        sessionHints));
     }
 
     private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -788,7 +789,8 @@
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        routerRecord, route, uniqueRequestId, null /* sessionHints */));
+                        routerRecord, managerRecord, route, uniqueRequestId,
+                        /* sessionHints= */ null));
     }
 
     private void selectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
@@ -927,7 +929,7 @@
         return ((long) routerOrManagerId << 32) | originalRequestId;
     }
 
-    static int toRouterOrManagerId(long uniqueRequestId) {
+    static int toRequesterId(long uniqueRequestId) {
         return (int) (uniqueRequestId >> 32);
     }
 
@@ -1107,11 +1109,6 @@
                     this, provider, sessionInfo, requestId));
         }
 
-        @Override
-        public void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId) {
-            sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreationFailedOnHandler,
-                    this, provider, requestId));
-        }
 
         @Override
         public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
@@ -1223,7 +1220,8 @@
         }
 
         private void requestCreateSessionOnHandler(@NonNull RouterRecord routerRecord,
-                @NonNull MediaRoute2Info route, long requestId, @Nullable Bundle sessionHints) {
+                @Nullable ManagerRecord managerRecord, @NonNull MediaRoute2Info route,
+                long requestId, @Nullable Bundle sessionHints) {
 
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider == null) {
@@ -1235,7 +1233,7 @@
 
             // TODO: Apply timeout for each request (How many seconds should we wait?)
             SessionCreationRequest request =
-                    new SessionCreationRequest(routerRecord, route, requestId);
+                    new SessionCreationRequest(routerRecord, managerRecord, route, requestId);
             mSessionCreationRequests.add(request);
 
             provider.requestCreateSession(routerRecord.mPackageName, route.getOriginalId(),
@@ -1421,30 +1419,6 @@
             mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
         }
 
-        private void onSessionCreationFailedOnHandler(@NonNull MediaRoute2Provider provider,
-                long requestId) {
-            SessionCreationRequest matchingRequest = null;
-
-            for (SessionCreationRequest request : mSessionCreationRequests) {
-                if (request.mRequestId == requestId
-                        && TextUtils.equals(
-                                request.mRoute.getProviderId(), provider.getUniqueId())) {
-                    matchingRequest = request;
-                    break;
-                }
-            }
-
-            if (matchingRequest == null) {
-                Slog.w(TAG, "Ignoring session creation failed result for unknown request. "
-                        + "requestId=" + requestId);
-                return;
-            }
-
-            mSessionCreationRequests.remove(matchingRequest);
-            notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
-                    toOriginalRequestId(requestId));
-        }
-
         private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
             List<IMediaRouter2Manager> managers = getManagers();
@@ -1483,30 +1457,56 @@
 
         private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
                 long requestId, int reason) {
-            final int managerId = toRouterOrManagerId(requestId);
-
-            MediaRouter2ServiceImpl service = mServiceRef.get();
-            if (service == null) {
+            if (handleSessionCreationRequestFailed(provider, requestId, reason)) {
                 return;
             }
 
-            ManagerRecord managerToNotifyFailure = null;
-            synchronized (service.mLock) {
-                for (ManagerRecord manager : mUserRecord.mManagerRecords) {
-                    if (manager.mManagerId == managerId) {
-                        managerToNotifyFailure = manager;
-                        break;
-                    }
+            final int requesterId = toRequesterId(requestId);
+            for (ManagerRecord manager : getManagerRecords()) {
+                if (manager.mManagerId == requesterId) {
+                    notifyRequestFailedToManager(
+                            manager.mManager, toOriginalRequestId(requestId), reason);
+                    return;
                 }
             }
 
-            if (managerToNotifyFailure == null) {
-                Slog.w(TAG, "No matching managerRecord found for managerId=" + managerId);
-                return;
+            // Currently, only the manager can get notified of failures.
+            // TODO: Notify router too when the related callback is introduced.
+        }
+
+        // TODO: Find a way to prevent providers from notifying error on random requestId.
+        //       Solutions can be:
+        //       1) Record the other type of requests too (not only session creation request)
+        //       2) Throw exception on providers when they try to notify error on random requestId.
+        private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
+                long requestId, int reason) {
+            // Check whether the failure is about creating a session
+            SessionCreationRequest matchingRequest = null;
+            for (SessionCreationRequest request : mSessionCreationRequests) {
+                if (request.mRequestId == requestId && TextUtils.equals(
+                        request.mRoute.getProviderId(), provider.getUniqueId())) {
+                    matchingRequest = request;
+                    break;
+                }
             }
 
-            notifyRequestFailedToManager(
-                    managerToNotifyFailure.mManager, toOriginalRequestId(requestId), reason);
+            if (matchingRequest == null) {
+                // The failure is not about creating a session.
+                return false;
+            }
+
+            mSessionCreationRequests.remove(matchingRequest);
+
+            // Notify the requester about the failure.
+            // The call should be made by either MediaRouter2 or MediaRouter2Manager.
+            if (matchingRequest.mRequestedManagerRecord == null) {
+                notifySessionCreationFailedToRouter(
+                        matchingRequest.mRouterRecord, toOriginalRequestId(requestId));
+            } else {
+                notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
+                        toOriginalRequestId(requestId), reason);
+            }
+            return true;
         }
 
         private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
@@ -1596,6 +1596,16 @@
             return managers;
         }
 
+        private List<ManagerRecord> getManagerRecords() {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return new ArrayList<>();
+            }
+            synchronized (service.mLock) {
+                return new ArrayList<>(mUserRecord.mManagerRecords);
+            }
+        }
+
         private void notifyRoutesToRouter(@NonNull IMediaRouter2 router) {
             List<MediaRoute2Info> routes = new ArrayList<>();
             for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
@@ -1789,12 +1799,16 @@
 
         final class SessionCreationRequest {
             public final RouterRecord mRouterRecord;
+            public final ManagerRecord mRequestedManagerRecord;
             public final MediaRoute2Info mRoute;
             public final long mRequestId;
 
+            // requestedManagerRecord is not null only when the request is made by manager.
             SessionCreationRequest(@NonNull RouterRecord routerRecord,
+                    @Nullable ManagerRecord requestedManagerRecord,
                     @NonNull MediaRoute2Info route, long requestId) {
                 mRouterRecord = routerRecord;
+                mRequestedManagerRecord = requestedManagerRecord;
                 mRoute = route;
                 mRequestId = requestId;
             }
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index da9c27e..1922c8c 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -127,7 +127,8 @@
     @Override
     public void requestCreateSession(String packageName, String routeId, long requestId,
             Bundle sessionHints) {
-        // Do nothing
+        // Handle it as an internal transfer.
+        transferToRoute(SYSTEM_SESSION_ID, routeId, requestId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b5e7ea0..e7553b6 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2189,19 +2189,19 @@
 
     private void registerNotificationPreferencesPullers() {
         mPullAtomCallback = new StatsPullAtomCallbackImpl();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_PREFERENCES,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
                 mPullAtomCallback
         );
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
                 mPullAtomCallback
         );
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 853c29c..799ce65 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18562,9 +18562,10 @@
                 Slog.d(TAG, "Updating package:" + ps.name + " install state for user:"
                         + nextUserId);
             }
-
-            destroyAppDataLIF(pkg, nextUserId,
-                    FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+            if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+                destroyAppDataLIF(pkg, nextUserId,
+                        FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+            }
             clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
             removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
             clearPackagePreferredActivities(ps.name, nextUserId);
@@ -19989,6 +19990,11 @@
         long token = Binder.clearCallingIdentity();
         try {
             if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
+                PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
+                if (packageInfo != null) {
+                    EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
+                            "");
+                }
                 return null;
             }
         } finally {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2bd1a26..a83a847 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -321,6 +321,8 @@
 
         Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
         updateMimeGroups(mimeGroupNames);
+
+        getPkgState().updateFrom(other.getPkgState());
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index e27bf48..edb6d65 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -27,6 +27,7 @@
 import com.android.internal.util.DataClass;
 import com.android.server.pm.PackageSetting;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -88,6 +89,22 @@
         return latestUse;
     }
 
+    public void updateFrom(PackageStateUnserialized other) {
+        this.hiddenUntilInstalled = other.hiddenUntilInstalled;
+
+        if (!other.usesLibraryInfos.isEmpty()) {
+            this.usesLibraryInfos = new ArrayList<>(other.usesLibraryInfos);
+        }
+
+        if (!other.usesLibraryFiles.isEmpty()) {
+            this.usesLibraryFiles = new ArrayList<>(other.usesLibraryFiles);
+        }
+
+        this.updatedSystemApp = other.updatedSystemApp;
+        this.lastPackageUsageTimeInMills = other.lastPackageUsageTimeInMills;
+        this.overrideSeInfo = other.overrideSeInfo;
+    }
+
 
 
     // Code below generated by codegen v1.0.14.
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 49a2901..1292f6c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -203,15 +203,18 @@
         checkPreemptPermissions();
         // Input validation (always valid).
 
-        synchronized (this) {
-            // State validation (always valid).
+        // State validation (always valid).
 
-            // From here on, every exception isn't client's fault.
-            try {
-                mDelegate.setExternalCaptureState(active);
-            } catch (Exception e) {
-                throw handleException(e);
-            }
+        // Normally, we would acquire a lock here. However, we do not access any state here so it
+        // is safe to not lock. This call is typically done from a different context than all the
+        // other calls and may result in a deadlock if we lock here (between the audio server and
+        // the system server).
+
+        // From here on, every exception isn't client's fault.
+        try {
+            mDelegate.setExternalCaptureState(active);
+        } catch (Exception e) {
+            throw handleException(e);
         }
     }
 
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 612989f..32cff3b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -182,7 +182,7 @@
      * How long to wait on an individual subsystem to return its stats.
      */
     private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
-    private static final long NS_PER_SEC = 1000000000;
+    private static final long MILLIS_PER_SEC = 1000;
     private static final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
 
     private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
@@ -680,7 +680,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3, 4, 5})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -772,7 +772,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3, 4, 5, 6})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -810,7 +810,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3, 4, 5})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -848,7 +848,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3, 4, 5, 6})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -886,7 +886,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -955,7 +955,7 @@
 
     private void registerKernelWakelock() {
         int tagId = FrameworkStatsLog.KERNEL_WAKELOCK;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* PullAtomMetadata */ null,
                 BackgroundThread.getExecutor(),
@@ -986,7 +986,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1017,7 +1017,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1046,7 +1046,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {4})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1078,7 +1078,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1105,7 +1105,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1130,7 +1130,7 @@
 
     private void registerWifiActivityInfo() {
         int tagId = FrameworkStatsLog.WIFI_ACTIVITY_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1182,7 +1182,7 @@
 
     private void registerModemActivityInfo() {
         int tagId = FrameworkStatsLog.MODEM_ACTIVITY_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1220,7 +1220,7 @@
 
     private void registerBluetoothActivityInfo() {
         int tagId = FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* metadata */ null,
                 BackgroundThread.getExecutor(),
@@ -1249,10 +1249,10 @@
     private void registerSystemElapsedRealtime() {
         int tagId = FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setCoolDownNs(NS_PER_SEC)
-                .setTimeoutNs(NS_PER_SEC / 2)
+                .setCoolDownMillis(MILLIS_PER_SEC)
+                .setTimeoutMillis(MILLIS_PER_SEC / 2)
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1271,7 +1271,7 @@
 
     private void registerSystemUptime() {
         int tagId = FrameworkStatsLog.SYSTEM_UPTIME;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1293,7 +1293,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {4, 5, 6, 7, 8})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1336,7 +1336,7 @@
 
     private void registerProcessMemoryHighWaterMark() {
         int tagId = FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1389,7 +1389,7 @@
 
     private void registerProcessMemorySnapshot() {
         int tagId = FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1449,7 +1449,7 @@
 
     private void registerSystemIonHeapSize() {
         int tagId = FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1472,7 +1472,7 @@
             return;
         }
         int tagId = FrameworkStatsLog.ION_HEAP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* PullAtomMetadata */ null,
                 BackgroundThread.getExecutor(),
@@ -1492,7 +1492,7 @@
 
     private void registerProcessSystemIonHeapSize() {
         int tagId = FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1518,7 +1518,7 @@
 
     private void registerTemperature() {
         int tagId = FrameworkStatsLog.TEMPERATURE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1556,7 +1556,7 @@
 
     private void registerCoolingDevice() {
         int tagId = FrameworkStatsLog.COOLING_DEVICE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1596,7 +1596,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {4, 5, 6, 8, 12})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1639,7 +1639,7 @@
 
     private void registerBinderCallsStatsExceptions() {
         int tagId = FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1674,7 +1674,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {5, 6, 7, 8, 9})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1716,7 +1716,7 @@
 
     private void registerDiskStats() {
         int tagId = FrameworkStatsLog.DISK_STATS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1782,7 +1782,7 @@
 
     private void registerDirectoryUsage() {
         int tagId = FrameworkStatsLog.DIRECTORY_USAGE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1823,7 +1823,7 @@
 
     private void registerAppSize() {
         int tagId = FrameworkStatsLog.APP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1867,7 +1867,7 @@
 
     private void registerCategorySize() {
         int tagId = FrameworkStatsLog.CATEGORY_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1971,7 +1971,7 @@
 
     private void registerNumFingerprintsEnrolled() {
         int tagId = FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1981,7 +1981,7 @@
 
     private void registerNumFacesEnrolled() {
         int tagId = FrameworkStatsLog.NUM_FACES_ENROLLED;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2039,7 +2039,7 @@
 
     private void registerProcStats() {
         int tagId = FrameworkStatsLog.PROC_STATS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2049,7 +2049,7 @@
 
     private void registerProcStatsPkgProc() {
         int tagId = FrameworkStatsLog.PROC_STATS_PKG_PROC;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2120,9 +2120,9 @@
         int tagId = FrameworkStatsLog.DISK_IO;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
-                .setCoolDownNs(3 * NS_PER_SEC)
+                .setCoolDownMillis(3 * MILLIS_PER_SEC)
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2155,7 +2155,7 @@
 
     private void registerPowerProfile() {
         int tagId = FrameworkStatsLog.POWER_PROFILE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* PullAtomMetadata */ null,
                 BackgroundThread.getExecutor(),
@@ -2180,9 +2180,9 @@
         int tagId = FrameworkStatsLog.PROCESS_CPU_TIME;
         // Min cool-down is 5 sec, in line with what ActivityManagerService uses.
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setCoolDownNs(5 * NS_PER_SEC)
+                .setCoolDownMillis(5 * MILLIS_PER_SEC)
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2217,7 +2217,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {7, 9, 11, 13, 15, 17, 19, 21})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2310,7 +2310,7 @@
 
     private void registerDeviceCalculatedPowerUse() {
         int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2330,7 +2330,7 @@
 
     private void registerDeviceCalculatedPowerBlameUid() {
         int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2360,7 +2360,7 @@
 
     private void registerDeviceCalculatedPowerBlameOther() {
         int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2396,7 +2396,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {1, 2, 3, 4})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2447,7 +2447,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {1, 2, 3, 4})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2485,7 +2485,7 @@
 
     private void registerBuildInformation() {
         int tagId = FrameworkStatsLog.BUILD_INFORMATION;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2512,7 +2512,7 @@
 
     private void registerRoleHolder() {
         int tagId = FrameworkStatsLog.ROLE_HOLDER;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2570,7 +2570,7 @@
 
     private void registerDangerousPermissionState() {
         int tagId = FrameworkStatsLog.DANGEROUS_PERMISSION_STATE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2660,7 +2660,7 @@
 
     private void registerTimeZoneDataInfo() {
         int tagId = FrameworkStatsLog.TIME_ZONE_DATA_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2687,7 +2687,7 @@
 
     private void registerExternalStorageInfo() {
         int tagId = FrameworkStatsLog.EXTERNAL_STORAGE_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2737,7 +2737,7 @@
 
     private void registerAppsOnExternalStorageInfo() {
         int tagId = FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2793,7 +2793,7 @@
 
     private void registerFaceSettings() {
         int tagId = FrameworkStatsLog.FACE_SETTINGS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2847,7 +2847,7 @@
 
     private void registerAppOps() {
         int tagId = FrameworkStatsLog.APP_OPS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2857,7 +2857,7 @@
 
     private void registerRuntimeAppOpAccessMessage() {
         int tagId = FrameworkStatsLog.RUNTIME_APP_OP_ACCESS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2927,7 +2927,7 @@
 
     private void registerAppFeaturesOps() {
         int tagId = FrameworkStatsLog.APP_FEATURES_OPS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3080,7 +3080,7 @@
 
     private void registerNotificationRemoteViews() {
         int tagId = FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3124,7 +3124,7 @@
 
     private void registerDangerousPermissionStateSampled() {
         int tagId = FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3134,7 +3134,7 @@
 
     private void registerBatteryLevel() {
         int tagId = FrameworkStatsLog.BATTERY_LEVEL;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3144,7 +3144,7 @@
 
     private void registerRemainingBatteryCapacity() {
         int tagId = FrameworkStatsLog.REMAINING_BATTERY_CAPACITY;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3154,7 +3154,7 @@
 
     private void registerFullBatteryCapacity() {
         int tagId = FrameworkStatsLog.FULL_BATTERY_CAPACITY;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3164,7 +3164,7 @@
 
     private void registerBatteryVoltage() {
         int tagId = FrameworkStatsLog.BATTERY_VOLTAGE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3174,7 +3174,7 @@
 
     private void registerBatteryCycleCount() {
         int tagId = FrameworkStatsLog.BATTERY_CYCLE_COUNT;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
index cddcabe..06c2354 100644
--- a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
+++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
@@ -30,6 +30,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.Collections;
 
@@ -140,7 +142,8 @@
         }
     }
 
-    private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
+    @VisibleForTesting
+    boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
         if (serviceInfo.permission == null || !serviceInfo.permission.equals(
                 Manifest.permission.BIND_TV_REMOTE_SERVICE)) {
             // If the service does not require this permission then any app could
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 61a33b4..d7a80bf 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1392,7 +1392,7 @@
                     tempWindowStatesList.add(w);
                 }
             }, false /* traverseTopToBottom */);
-            // Insert the re-parented windows in another display on top of their parents in
+            // Insert the re-parented windows in another display below their parents in
             // default display.
             mService.mRoot.forAllWindows(w -> {
                 final WindowState parentWindow = findRootDisplayParentWindow(w);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index acb9900..7a30211 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7628,6 +7628,11 @@
     }
 
     @Override
+    boolean canCreateRemoteAnimationTarget() {
+        return true;
+    }
+
+    @Override
     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
             Rect outSurfaceInsets) {
         final WindowState win = findMainWindow();
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index bc12923..420675c 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1469,11 +1469,11 @@
 
         if (resumeNext) {
             final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
-            if (!topStack.shouldSleepOrShutDownActivities()) {
+            if (topStack != null && !topStack.shouldSleepOrShutDownActivities()) {
                 mRootWindowContainer.resumeFocusedStacksTopActivities(topStack, prev, null);
             } else {
                 checkReadyForSleep();
-                ActivityRecord top = topStack.topRunningActivity();
+                final ActivityRecord top = topStack != null ? topStack.topRunningActivity() : null;
                 if (top == null || (prev != null && top != prev)) {
                     // If there are no more activities available to run, do resume anyway to start
                     // something. Also if the top activity on the stack is not the just paused
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 3210304..984ae21 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -615,12 +615,15 @@
 
             int res;
             synchronized (mService.mGlobalLock) {
-                final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
-                stack.mConfigWillChange = mRequest.globalConfig != null
+                final boolean globalConfigWillChange = mRequest.globalConfig != null
                         && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
+                final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
+                if (stack != null) {
+                    stack.mConfigWillChange = globalConfigWillChange;
+                }
                 if (DEBUG_CONFIGURATION) {
                     Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
-                            + stack.mConfigWillChange);
+                            + globalConfigWillChange);
                 }
 
                 final long origId = Binder.clearCallingIdentity();
@@ -633,7 +636,7 @@
 
                 Binder.restoreCallingIdentity(origId);
 
-                if (stack.mConfigWillChange) {
+                if (globalConfigWillChange) {
                     // If the caller also wants to switch to a new configuration, do so now.
                     // This allows a clean switch, as we are waiting for the current activity
                     // to pause (so we will not destroy it), and have not yet started the
@@ -641,7 +644,9 @@
                     mService.mAmInternal.enforceCallingPermission(
                             android.Manifest.permission.CHANGE_CONFIGURATION,
                             "updateConfiguration()");
-                    stack.mConfigWillChange = false;
+                    if (stack != null) {
+                        stack.mConfigWillChange = false;
+                    }
                     if (DEBUG_CONFIGURATION) {
                         Slog.v(TAG_CONFIGURATION,
                                 "Updating to new configuration after starting activity.");
@@ -1536,9 +1541,11 @@
         // If the activity being launched is the same as the one currently at the top, then
         // we need to check if it should only be launched once.
         final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
-        startResult = deliverToCurrentTopIfNeeded(topStack);
-        if (startResult != START_SUCCESS) {
-            return startResult;
+        if (topStack != null) {
+            startResult = deliverToCurrentTopIfNeeded(topStack);
+            if (startResult != START_SUCCESS) {
+                return startResult;
+            }
         }
 
         if (mTargetStack == null) {
@@ -2126,10 +2133,13 @@
         if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
             ActivityRecord checkedCaller = sourceRecord;
             if (checkedCaller == null) {
-                checkedCaller = mRootWindowContainer.getTopDisplayFocusedStack()
-                        .topRunningNonDelayedActivityLocked(mNotTop);
+                ActivityStack topFocusedStack = mRootWindowContainer.getTopDisplayFocusedStack();
+                if (topFocusedStack != null) {
+                    checkedCaller = topFocusedStack.topRunningNonDelayedActivityLocked(mNotTop);
+                }
             }
-            if (!checkedCaller.mActivityComponent.equals(r.mActivityComponent)) {
+            if (checkedCaller == null
+                    || !checkedCaller.mActivityComponent.equals(r.mActivityComponent)) {
                 // Caller is not the same as launcher, so always needed.
                 mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
             }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 98c8b61..911812b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1104,8 +1104,8 @@
             // If this is coming from the currently resumed activity, it is
             // effectively saying that app switches are allowed at this point.
             final ActivityStack stack = getTopDisplayFocusedStack();
-            if (stack.mResumedActivity != null &&
-                    stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
+            if (stack != null && stack.mResumedActivity != null
+                    && stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
                 mAppSwitchesAllowedTime = 0;
             }
         }
@@ -1951,8 +1951,13 @@
     public boolean isTopActivityImmersive() {
         enforceNotIsolatedCaller("isTopActivityImmersive");
         synchronized (mGlobalLock) {
-            final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
-            return (r != null) ? r.immersive : false;
+            final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+            if (topFocusedStack == null) {
+                return false;
+            }
+
+            final ActivityRecord r = topFocusedStack.topRunningActivity();
+            return r != null && r.immersive;
         }
     }
 
@@ -1981,7 +1986,8 @@
     public int getFrontActivityScreenCompatMode() {
         enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
         synchronized (mGlobalLock) {
-            final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
+            final ActivityStack stack = getTopDisplayFocusedStack();
+            final ActivityRecord r = stack != null ? stack.topRunningActivity() : null;
             if (r == null) {
                 return ActivityManager.COMPAT_MODE_UNKNOWN;
             }
@@ -1995,7 +2001,8 @@
                 "setFrontActivityScreenCompatMode");
         ApplicationInfo ai;
         synchronized (mGlobalLock) {
-            final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
+            final ActivityStack stack = getTopDisplayFocusedStack();
+            final ActivityRecord r = stack != null ? stack.topRunningActivity() : null;
             if (r == null) {
                 Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
                 return;
@@ -2383,7 +2390,10 @@
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
-                getTopDisplayFocusedStack().unhandledBackLocked();
+                final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+                if (topFocusedStack != null) {
+                    topFocusedStack.unhandledBackLocked();
+                }
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -3616,7 +3626,8 @@
                 "enqueueAssistContext()");
 
         synchronized (mGlobalLock) {
-            ActivityRecord activity = getTopDisplayFocusedStack().getTopNonFinishingActivity();
+            final ActivityStack stack = getTopDisplayFocusedStack();
+            ActivityRecord activity = stack != null ? stack.getTopNonFinishingActivity() : null;
             if (activity == null) {
                 Slog.w(TAG, "getAssistContextExtras failed: no top activity");
                 return null;
@@ -7037,9 +7048,9 @@
                     mRootWindowContainer.dumpDisplayConfigs(pw, "  ");
                 }
                 if (dumpAll) {
-                    if (dumpPackage == null) {
-                        pw.println("  mConfigWillChange: "
-                                + getTopDisplayFocusedStack().mConfigWillChange);
+                    final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+                    if (dumpPackage == null && topFocusedStack != null) {
+                        pw.println("  mConfigWillChange: " + topFocusedStack.mConfigWillChange);
                     }
                     if (mCompatModePackages.getPackages().size() > 0) {
                         boolean printed = false;
@@ -7120,7 +7131,10 @@
             synchronized (mGlobalLock) {
                 if (dumpPackage == null) {
                     getGlobalConfiguration().dumpDebug(proto, GLOBAL_CONFIGURATION);
-                    proto.write(CONFIG_WILL_CHANGE, getTopDisplayFocusedStack().mConfigWillChange);
+                    final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+                    if (topFocusedStack != null) {
+                        proto.write(CONFIG_WILL_CHANGE, topFocusedStack.mConfigWillChange);
+                    }
                     writeSleepStateToProto(proto, wakeFullness, testPssMode);
                     if (mRunningVoice != null) {
                         final long vrToken = proto.start(
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 0912b2e..6a47c9e 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -446,7 +446,7 @@
             siblings.add(current);
             boolean canPromote = true;
 
-            if (parent == null) {
+            if (parent == null || !parent.canCreateRemoteAnimationTarget()) {
                 canPromote = false;
             } else {
                 // In case a descendant of the parent belongs to the other group, we cannot promote
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ada5685..74c3044 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1980,7 +1980,9 @@
     }
 
     boolean switchUser(int userId, UserState uss) {
-        final int focusStackId = getTopDisplayFocusedStack().getRootTaskId();
+        final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+        final int focusStackId = topFocusedStack != null
+                ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
         // We dismiss the docked stack whenever we switch users.
         final ActivityStack dockedStack = getDefaultDisplay().getRootSplitScreenPrimaryTask();
         if (dockedStack != null) {
@@ -3455,7 +3457,12 @@
     ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleStacksOnly,
             boolean dumpFocusedStackOnly) {
         if (dumpFocusedStackOnly) {
-            return getTopDisplayFocusedStack().getDumpActivitiesLocked(name);
+            final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+            if (topFocusedStack != null) {
+                return topFocusedStack.getDumpActivitiesLocked(name);
+            } else {
+                return new ArrayList<>();
+            }
         } else {
             ArrayList<ActivityRecord> activities = new ArrayList<>();
             int numDisplays = getChildCount();
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3b3234a..19f8ca9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -379,10 +379,8 @@
         final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
                 .setParent(animatable.getAnimationLeashParent())
                 .setHidden(hidden)
-                .setName(surface + " - animation-leash")
-                .setColorLayer();
+                .setName(surface + " - animation-leash");
         final SurfaceControl leash = builder.build();
-        t.unsetColor(leash);
         t.setWindowCrop(leash, width, height);
         t.setPosition(leash, x, y);
         t.show(leash);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index faa6bac8..88d4fb3 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3121,6 +3121,11 @@
         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
     }
 
+    @Override
+    boolean canCreateRemoteAnimationTarget() {
+        return true;
+    }
+
     WindowState getTopVisibleAppMainWindow() {
         final ActivityRecord activity = getTopVisibleActivity();
         return activity != null ? activity.findMainWindow() : null;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8f5d048..b38c18b 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -463,8 +463,9 @@
         int configMask = change.getConfigSetMask();
         int windowMask = change.getWindowSetMask();
         configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
-                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
-        windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE;
+        windowMask &= (WindowConfiguration.WINDOW_CONFIG_BOUNDS
+                | WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS);
         int effects = 0;
         if (configMask != 0) {
             Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
index 74d5c33..205b423 100644
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -147,7 +147,7 @@
      */
     void updateResolvedConfig(Configuration inOutResolvedConfig) {
         Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
-        if (resolveBounds == null || resolveBounds.isEmpty()) {
+        if (resolveBounds.isEmpty()) {
             resolveBounds.set(getRequestedOverrideBounds());
         }
         int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
@@ -162,6 +162,17 @@
             inOutResolvedConfig.smallestScreenWidthDp =
                     getRequestedOverrideConfiguration().smallestScreenWidthDp;
         }
+        if (inOutResolvedConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+            inOutResolvedConfig.screenWidthDp = getRequestedOverrideConfiguration().screenWidthDp;
+        }
+        if (inOutResolvedConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+            inOutResolvedConfig.screenHeightDp = getRequestedOverrideConfiguration().screenHeightDp;
+        }
+        Rect resolveAppBounds = inOutResolvedConfig.windowConfiguration.getAppBounds();
+        if (resolveAppBounds == null || resolveAppBounds.isEmpty()) {
+            inOutResolvedConfig.windowConfiguration.setAppBounds(
+                    getRequestedOverrideConfiguration().windowConfiguration.getAppBounds());
+        }
     }
 
     @Override
@@ -184,7 +195,6 @@
         boolean isResizable = topTask == null || topTask.isResizeable();
         info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
         info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
-        info.configuration.setTo(getRequestedOverrideConfiguration());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b12c698..10d34b5 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2196,6 +2196,10 @@
         return null;
     }
 
+    boolean canCreateRemoteAnimationTarget() {
+        return false;
+    }
+
     boolean okToDisplay() {
         final DisplayContent dc = getDisplayContent();
         return dc != null && dc.okToDisplay();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f140ce8..27f1ca0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -657,7 +657,7 @@
     private boolean mIsDimming = false;
 
     private @Nullable InsetsSourceProvider mControllableInsetProvider;
-    private InsetsState mRequestedInsetsState;
+    private final InsetsState mRequestedInsetsState = new InsetsState();
 
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
     private KeyInterceptionInfo mKeyInterceptionInfo;
@@ -816,9 +816,6 @@
         mSeq = seq;
         mPowerManagerWrapper = powerManagerWrapper;
         mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
-        mRequestedInsetsState = new InsetsState(
-                getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this),
-                true /* copySources */);
         if (DEBUG) {
             Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
                             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd
index a70568f..5a4c682 100644
--- a/services/core/xsd/platform-compat-config.xsd
+++ b/services/core/xsd/platform-compat-config.xsd
@@ -27,6 +27,7 @@
                 <xs:attribute type="xs:long" name="id" use="required"/>
                 <xs:attribute type="xs:string" name="name" use="required"/>
                 <xs:attribute type="xs:boolean" name="disabled"/>
+                <xs:attribute type="xs:boolean" name="loggingOnly"/>
                 <xs:attribute type="xs:int" name="enableAfterTargetSdk"/>
                 <xs:attribute type="xs:string" name="description"/>
             </xs:extension>
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt
index 3a33f63..7def58d 100644
--- a/services/core/xsd/platform-compat-schema/current.txt
+++ b/services/core/xsd/platform-compat-schema/current.txt
@@ -7,12 +7,14 @@
     method public boolean getDisabled();
     method public int getEnableAfterTargetSdk();
     method public long getId();
+    method public boolean getLoggingOnly();
     method public String getName();
     method public String getValue();
     method public void setDescription(String);
     method public void setDisabled(boolean);
     method public void setEnableAfterTargetSdk(int);
     method public void setId(long);
+    method public void setLoggingOnly(boolean);
     method public void setName(String);
     method public void setValue(String);
   }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1de704d..c58eae1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2691,6 +2691,27 @@
         }
     }
 
+    /**
+     * If the device is in Device Owner mode, apply the restriction on adding
+     * a managed profile.
+     */
+    @GuardedBy("getLockObject()")
+    void applyManagedProfileRestrictionIfDeviceOwnerLocked() {
+        final int doUserId = mOwners.getDeviceOwnerUserId();
+        if (doUserId == UserHandle.USER_NULL) {
+            logIfVerbose("No DO found, skipping application of restriction.");
+            return;
+        }
+
+        final UserHandle doUserHandle = UserHandle.of(doUserId);
+        // Set the restriction if not set.
+        if (!mUserManager.hasUserRestriction(
+                UserManager.DISALLOW_ADD_MANAGED_PROFILE, doUserHandle)) {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                    doUserHandle);
+        }
+    }
+
     /** Apply default restrictions that haven't been applied to profile owners yet. */
     private void maybeSetDefaultProfileOwnerUserRestrictions() {
         synchronized (getLockObject()) {
@@ -3901,6 +3922,7 @@
                 maybeStartSecurityLogMonitorOnActivityManagerReady();
                 synchronized (getLockObject()) {
                     migrateToProfileOnOrganizationOwnedDeviceIfCompLocked();
+                    applyManagedProfileRestrictionIfDeviceOwnerLocked();
                 }
                 final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
                 if (userId >= 0) {
@@ -8764,6 +8786,7 @@
         mOwners.writeProfileOwner(userId);
         deleteTransferOwnershipBundleLocked(userId);
         toggleBackupServiceActive(userId, true);
+        applyManagedProfileRestrictionIfDeviceOwnerLocked();
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 107b0a1..b019e9d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -294,8 +294,6 @@
             "com.android.server.DeviceIdleController";
     private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
             "com.android.server.blob.BlobStoreManagerService";
-    private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
-            "com.android.server.appsearch.AppSearchManagerService";
 
     private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
 
@@ -2178,10 +2176,6 @@
         mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
         t.traceEnd();
 
-        t.traceBegin("AppSearchManagerService");
-        mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
-        t.traceEnd();
-
         ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
                 START_BLOB_STORE_SERVICE);
 
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 983a639..37bf664 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -72,13 +72,13 @@
     }
 
     @Override
-    public void onUserUnlocking(@NonNull TargetUser targetUser) {
-        mDataManager.onUserUnlocked(targetUser.getUserIdentifier());
+    public void onUserUnlocked(@NonNull TargetUser user) {
+        mDataManager.onUserUnlocked(user.getUserIdentifier());
     }
 
     @Override
-    public void onUserStopping(@NonNull TargetUser targetUser) {
-        mDataManager.onUserStopped(targetUser.getUserIdentifier());
+    public void onUserStopping(@NonNull TargetUser user) {
+        mDataManager.onUserStopping(user.getUserIdentifier());
     }
 
     @VisibleForTesting
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index e4ce6ba..4e0afc5 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -198,13 +198,13 @@
         DataMaintenanceService.scheduleJob(mContext, userId);
     }
 
-    /** This method is called when a user is stopped. */
-    public void onUserStopped(int userId) {
+    /** This method is called when a user is stopping. */
+    public void onUserStopping(int userId) {
         if (mUserDataArray.indexOfKey(userId) >= 0) {
             mUserDataArray.get(userId).setUserStopped();
         }
         if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
-            mUsageStatsQueryFutures.valueAt(userId).cancel(true);
+            mUsageStatsQueryFutures.get(userId).cancel(true);
         }
         if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
             mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d148c21..449e75c 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -43,7 +43,6 @@
         "platformprotosnano",
         "hamcrest-library",
         "servicestests-utils",
-        "service-appsearch",
         "service-jobscheduler",
         "service-permission",
         // TODO: remove once Android migrates to JUnit 4.12,
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java
deleted file mode 100644
index 34ade81..0000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.expectThrows;
-
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.os.UserHandle;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.icing.proto.IndexingConfig;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class AppSearchImplTest {
-    private final Context mContext = InstrumentationRegistry.getContext();
-    private final @UserIdInt int mUserId = UserHandle.getCallingUserId();
-
-    @Test
-    public void testRewriteSchemaTypes() {
-        SchemaProto inSchema = SchemaProto.newBuilder()
-                .addTypes(SchemaTypeConfigProto.newBuilder()
-                        .setSchemaType("TestType")
-                        .addProperties(PropertyConfigProto.newBuilder()
-                                .setPropertyName("subject")
-                                .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                                .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                                .setIndexingConfig(
-                                        IndexingConfig.newBuilder()
-                                                .setTokenizerType(
-                                                        IndexingConfig.TokenizerType.Code.PLAIN)
-                                                .setTermMatchType(TermMatchType.Code.PREFIX)
-                                                .build()
-                                ).build()
-                        ).addProperties(PropertyConfigProto.newBuilder()
-                                .setPropertyName("link")
-                                .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
-                                .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                                .setSchemaType("RefType")
-                                .build()
-                        ).build()
-                ).build();
-
-        SchemaProto expectedSchema = SchemaProto.newBuilder()
-                .addTypes(SchemaTypeConfigProto.newBuilder()
-                        .setSchemaType("com.android.server.appsearch.impl@42:TestType")
-                        .addProperties(PropertyConfigProto.newBuilder()
-                                .setPropertyName("subject")
-                                .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                                .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                                .setIndexingConfig(
-                                        IndexingConfig.newBuilder()
-                                                .setTokenizerType(
-                                                        IndexingConfig.TokenizerType.Code.PLAIN)
-                                                .setTermMatchType(TermMatchType.Code.PREFIX)
-                                                .build()
-                                ).build()
-                        ).addProperties(PropertyConfigProto.newBuilder()
-                                .setPropertyName("link")
-                                .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
-                                .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                                .setSchemaType("com.android.server.appsearch.impl@42:RefType")
-                                .build()
-                        ).build()
-                ).build();
-
-        AppSearchImpl impl = new AppSearchImpl(mContext, mUserId);
-        SchemaProto.Builder actualSchema = inSchema.toBuilder();
-        impl.rewriteSchemaTypes("com.android.server.appsearch.impl@42:", actualSchema);
-
-        assertThat(actualSchema.build()).isEqualTo(expectedSchema);
-    }
-
-    @Test
-    public void testPackageNotFound() {
-        AppSearchImpl impl = new AppSearchImpl(mContext, mUserId);
-        IllegalStateException e = expectThrows(
-                IllegalStateException.class,
-                () -> impl.setSchema(
-                        /*callingUid=*/Integer.MAX_VALUE,
-                        SchemaProto.getDefaultInstance(),
-                        /*forceOverride=*/false));
-        assertThat(e).hasMessageThat().contains("Failed to look up package name");
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
deleted file mode 100644
index 07b6556..0000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.StatusProto;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-public class FakeIcingTest {
-    @Test
-    public void query() {
-        FakeIcing icing = new FakeIcing();
-        icing.put(createDoc("uri:cat", "The cat said meow"));
-        icing.put(createDoc("uri:dog", "The dog said woof"));
-
-        assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
-        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
-        assertThat(queryGetUris(icing, "fred")).isEmpty();
-    }
-
-    @Test
-    public void queryNorm() {
-        FakeIcing icing = new FakeIcing();
-        icing.put(createDoc("uri:cat", "The cat said meow"));
-        icing.put(createDoc("uri:dog", "The dog said woof"));
-
-        assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog");
-        assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog");
-        assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog");
-    }
-
-    @Test
-    public void get() {
-        DocumentProto cat = createDoc("uri:cat", "The cat said meow");
-        FakeIcing icing = new FakeIcing();
-        icing.put(cat);
-        assertThat(icing.get("uri:cat")).isEqualTo(cat);
-    }
-
-    @Test
-    public void replace() {
-        DocumentProto cat = createDoc("uri:cat", "The cat said meow");
-        DocumentProto dog = createDoc("uri:dog", "The dog said woof");
-
-        FakeIcing icing = new FakeIcing();
-        icing.put(cat);
-        icing.put(dog);
-
-        assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
-        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.get("uri:cat")).isEqualTo(cat);
-
-        // Replace
-        DocumentProto cat2 = createDoc("uri:cat", "The cat said purr");
-        DocumentProto bird = createDoc("uri:bird", "The cat said tweet");
-        icing.put(cat2);
-        icing.put(bird);
-
-        assertThat(queryGetUris(icing, "meow")).isEmpty();
-        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
-        assertThat(icing.get("uri:cat")).isEqualTo(cat2);
-    }
-
-    @Test
-    public void delete() {
-        DocumentProto cat = createDoc("uri:cat", "The cat said meow");
-        DocumentProto dog = createDoc("uri:dog", "The dog said woof");
-
-        FakeIcing icing = new FakeIcing();
-        icing.put(cat);
-        icing.put(dog);
-
-        assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
-        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.get("uri:cat")).isEqualTo(cat);
-
-        // Delete
-        icing.delete("uri:cat");
-        icing.delete("uri:notreal");
-
-        assertThat(queryGetUris(icing, "meow")).isEmpty();
-        assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog");
-        assertThat(icing.get("uri:cat")).isNull();
-    }
-
-    private static DocumentProto createDoc(String uri, String body) {
-        return DocumentProto.newBuilder()
-                .setUri(uri)
-                .addProperties(PropertyProto.newBuilder().addStringValues(body))
-                .build();
-    }
-
-    private static List<String> queryGetUris(FakeIcing icing, String term) {
-        List<String> uris = new ArrayList<>();
-        SearchResultProto results = icing.query(term);
-        assertThat(results.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
-        for (SearchResultProto.ResultProto result : results.getResultsList()) {
-            uris.add(result.getDocument().getUri());
-        }
-        return uris;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index 328c71d..2cbe7be 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -40,52 +40,57 @@
     }
 
     CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
-        mChanges.add(new CompatChange(id, "", sdk, false, ""));
+        mChanges.add(new CompatChange(id, "", sdk, false, false, ""));
         return this;
     }
 
     CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
-        mChanges.add(new CompatChange(id, "", sdk, true, ""));
+        mChanges.add(new CompatChange(id, "", sdk, true, false, ""));
         return this;
     }
 
     CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
-        mChanges.add(new CompatChange(id, name, sdk, false, ""));
+        mChanges.add(new CompatChange(id, name, sdk, false, false, ""));
         return this;
     }
 
     CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
             String description) {
-        mChanges.add(new CompatChange(id, "", sdk, false, description));
+        mChanges.add(new CompatChange(id, "", sdk, false, false, description));
         return this;
     }
 
     CompatConfigBuilder addEnabledChangeWithId(long id) {
-        mChanges.add(new CompatChange(id, "", -1, false, ""));
+        mChanges.add(new CompatChange(id, "", -1, false, false, ""));
         return this;
     }
 
     CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
-        mChanges.add(new CompatChange(id, name, -1, false, ""));
+        mChanges.add(new CompatChange(id, name, -1, false, false, ""));
         return this;
     }
     CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
-        mChanges.add(new CompatChange(id, "", -1, false, description));
+        mChanges.add(new CompatChange(id, "", -1, false, false, description));
         return this;
     }
 
     CompatConfigBuilder addDisabledChangeWithId(long id) {
-        mChanges.add(new CompatChange(id, "", -1, true, ""));
+        mChanges.add(new CompatChange(id, "", -1, true, false, ""));
         return this;
     }
 
     CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
-        mChanges.add(new CompatChange(id, name, -1, true, ""));
+        mChanges.add(new CompatChange(id, name, -1, true, false, ""));
         return this;
     }
 
     CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
-        mChanges.add(new CompatChange(id, "", -1, true, description));
+        mChanges.add(new CompatChange(id, "", -1, true, false, description));
+        return this;
+    }
+
+    CompatConfigBuilder addLoggingOnlyChangeWithId(long id) {
+        mChanges.add(new CompatChange(id, "", -1, false, true, ""));
         return this;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 44f4ccf..eb2dd64 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -214,6 +214,17 @@
     }
 
     @Test
+    public void testLoggingOnlyChangePreventAddOverride() throws Exception {
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addLoggingOnlyChangeWithId(1234L)
+                .build();
+
+        assertThrows(SecurityException.class,
+                () -> compatConfig.addOverride(1234L, "com.some.package", true)
+        );
+    }
+
+    @Test
     public void testPreventRemoveOverride() throws Exception {
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addDisabledChangeWithId(1234L)
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index b14291b..16291b2 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -20,6 +20,7 @@
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -78,6 +79,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        android.app.compat.ChangeIdStateCache.disable();
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
     }
 
@@ -89,7 +91,8 @@
                     .addTargetSdkChangeWithId(TARGET_SDK, 2)
                     .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                     .addEnabledChangeWithId(4)
-                    .addDisabledChangeWithId(5).build();
+                    .addDisabledChangeWithId(5)
+                    .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -107,6 +110,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
@@ -118,6 +123,8 @@
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 
     @Test
@@ -128,7 +135,8 @@
                     .addTargetSdkChangeWithId(TARGET_SDK, 2)
                     .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                     .addEnabledChangeWithId(4)
-                    .addDisabledChangeWithId(5).build();
+                    .addDisabledChangeWithId(5)
+                    .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -145,6 +153,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
@@ -156,6 +166,8 @@
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 
     @Test
@@ -232,7 +244,8 @@
                         .addTargetSdkChangeWithId(TARGET_SDK, 2)
                         .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                         .addEnabledChangeWithId(4)
-                        .addDisabledChangeWithId(5).build();
+                        .addDisabledChangeWithId(5)
+                        .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -249,6 +262,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
@@ -260,6 +275,8 @@
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 
     @Test
@@ -351,7 +368,8 @@
                         .addTargetSdkChangeWithId(TARGET_SDK, 2)
                         .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                         .addEnabledChangeWithId(4)
-                        .addDisabledChangeWithId(5).build();
+                        .addDisabledChangeWithId(5)
+                        .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -368,6 +386,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
@@ -379,5 +399,7 @@
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
index 891ca74..0e4d2be 100644
--- a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
@@ -16,30 +16,52 @@
 
 package com.android.server.content;
 
-import java.util.ArrayList;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.content.ContentResolver;
 import android.database.ContentObserver;
+import android.database.IContentObserver;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
 
-import com.android.server.content.ContentService.ObserverCall;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.content.ContentService.ObserverCollector;
 import com.android.server.content.ContentService.ObserverNode;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+import java.util.Arrays;
+
 /**
  * atest FrameworksServicesTests:com.android.server.content.ObserverNodeTest
  */
-@SmallTest
-public class ObserverNodeTest extends AndroidTestCase {
-    static class TestObserver  extends ContentObserver {
+@RunWith(AndroidJUnit4.class)
+public class ObserverNodeTest {
+    static class TestObserver extends ContentObserver {
         public TestObserver() {
             super(new Handler(Looper.getMainLooper()));
         }
     }
 
+    @Test
     public void testUri() {
         final int myUserHandle = UserHandle.myUserId();
 
@@ -65,15 +87,15 @@
                     0, 0, myUserHandle);
         }
 
-        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
-
         for (int i = nums.length - 1; i >=0; --i) {
-            root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, calls);
-            assertEquals(nums[i], calls.size());
-            calls.clear();
+            final ObserverCollector collector = mock(ObserverCollector.class);
+            root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, collector);
+            verify(collector, times(nums[i])).collect(
+                    any(), anyInt(), anyBoolean(), any(), anyInt(), anyInt());
         }
     }
 
+    @Test
     public void testUriNotNotify() {
         final int myUserHandle = UserHandle.myUserId();
 
@@ -95,12 +117,67 @@
                     0, 0, myUserHandle);
         }
 
-        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
-
         for (int i = uris.length - 1; i >=0; --i) {
-            root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, calls);
-            assertEquals(nums[i], calls.size());
-            calls.clear();
+            final ObserverCollector collector = mock(ObserverCollector.class);
+            root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, collector);
+            verify(collector, times(nums[i])).collect(
+                    any(), anyInt(), anyBoolean(), any(), anyInt(), anyInt());
+        }
+    }
+
+    @Test
+    public void testCluster() throws Exception {
+        final int myUserHandle = UserHandle.myUserId();
+
+        // Assume everything is foreground during our test
+        final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
+        when(ami.getUidProcessState(anyInt()))
+                .thenReturn(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.addService(ActivityManagerInternal.class, ami);
+
+        final IContentObserver observer = mock(IContentObserver.class);
+        when(observer.asBinder()).thenReturn(new Binder());
+
+        final ObserverNode root = new ObserverNode("");
+        root.addObserverLocked(Uri.parse("content://authority/"), observer,
+                true, root, 0, 1000, myUserHandle);
+
+        final ObserverCollector collector = new ObserverCollector();
+        root.collectObserversLocked(Uri.parse("content://authority/1"), 0, null, false,
+                0, myUserHandle, collector);
+        root.collectObserversLocked(Uri.parse("content://authority/1"), 0, null, false,
+                ContentResolver.NOTIFY_INSERT, myUserHandle, collector);
+        root.collectObserversLocked(Uri.parse("content://authority/2"), 0, null, false,
+                ContentResolver.NOTIFY_INSERT, myUserHandle, collector);
+        root.collectObserversLocked(Uri.parse("content://authority/2"), 0, null, false,
+                ContentResolver.NOTIFY_UPDATE, myUserHandle, collector);
+        collector.dispatch();
+
+        // We should only cluster when all other arguments are equal
+        verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher(
+                        Uri.parse("content://authority/1"))),
+                eq(0), anyInt());
+        verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher(
+                        Uri.parse("content://authority/1"),
+                        Uri.parse("content://authority/2"))),
+                eq(ContentResolver.NOTIFY_INSERT), anyInt());
+        verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher(
+                        Uri.parse("content://authority/2"))),
+                eq(ContentResolver.NOTIFY_UPDATE), anyInt());
+    }
+
+    private static class UriSetMatcher implements ArgumentMatcher<Uri[]> {
+        private final ArraySet<Uri> uris;
+
+        public UriSetMatcher(Uri... uris) {
+            this.uris = new ArraySet<>(Arrays.asList(uris));
+        }
+
+        @Override
+        public boolean matches(Uri[] uris) {
+            final ArraySet<Uri> test = new ArraySet<>(Arrays.asList(uris));
+            return this.uris.equals(test);
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 2e77c9f..684bbd4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -236,6 +236,7 @@
     @Test
     public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
             throws Exception {
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
         initializeStorageWithCredential(
                 MANAGED_PROFILE_USER_ID,
                 newPattern("12345"),
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 624b67c..a4d63ac 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -269,7 +269,7 @@
         assertEquals(1, conversations.size());
         assertEquals("sc_1", conversations.get(0).getShortcutId());
 
-        mDataManager.onUserStopped(USER_ID_PRIMARY);
+        mDataManager.onUserStopping(USER_ID_PRIMARY);
         conversations = getConversationsInPrimary();
         assertTrue(conversations.isEmpty());
     }
diff --git a/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java
new file mode 100644
index 0000000..0a2bb62
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.tv;
+
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.os.Looper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class TvRemoteProviderWatcherTest {
+    private static final String TV_REMOTE_SERVICE_PACKAGE_NAME =
+            "com.google.android.tv.remote.service";
+
+    @Mock
+    Context mMockContext;
+    @Mock
+    PackageManager mMockPackageManager;
+    @Mock
+    Resources mMockResources;
+
+    private TvRemoteProviderWatcher mTvRemoteProviderWatcher;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+
+        when(mMockResources.getString(com.android.internal.R.string.config_tvRemoteServicePackage))
+                .thenReturn(TV_REMOTE_SERVICE_PACKAGE_NAME);
+
+
+        when(mMockPackageManager.checkPermission(
+                argThat(not(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER)),
+                anyString())).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        when(mMockPackageManager.checkPermission(
+                anyString(),
+                argThat(not(TV_REMOTE_SERVICE_PACKAGE_NAME)))).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        when(mMockPackageManager.checkPermission(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER,
+                TV_REMOTE_SERVICE_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        mTvRemoteProviderWatcher = new TvRemoteProviderWatcher(mMockContext, new Object());
+    }
+
+    @Test
+    public void tvServiceIsTrusted() {
+        assertTrue(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo()));
+    }
+
+    @Test
+    public void permissionIsRequired() {
+        ServiceInfo serviceInfo = createTvServiceInfo();
+        serviceInfo.permission = null;
+
+        assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo));
+    }
+
+    @Test
+    public void permissionMustBeBindRemote() {
+        ServiceInfo serviceInfo = createTvServiceInfo();
+        serviceInfo.permission = Manifest.permission.BIND_TV_INPUT;
+        assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo));
+    }
+
+    @Test
+    public void packageNameMustMatch() {
+        ServiceInfo serviceInfo = createTvServiceInfo();
+        serviceInfo.packageName = "some.random.package";
+        assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo));
+    }
+
+    @Test
+    public void packageManagerPermissionIsRequired() {
+        reset(mMockPackageManager);
+        when(mMockPackageManager.checkPermission(anyString(), anyString())).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo()));
+    }
+
+    @Test
+    public void whitelistingPackageNameIsRequired() {
+        reset(mMockResources);
+        when(mMockResources.getString(anyInt())).thenReturn("");
+
+        // Create a new watcher, as the resources are read in the constructor of the class
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        TvRemoteProviderWatcher watcher =
+                new TvRemoteProviderWatcher(mMockContext, new Object());
+        assertFalse(watcher.verifyServiceTrusted(createTvServiceInfo()));
+    }
+
+    private ServiceInfo createTvServiceInfo() {
+        ServiceInfo serviceInfo = new ServiceInfo();
+
+        serviceInfo.name = "ATV Remote Service";
+        serviceInfo.packageName = TV_REMOTE_SERVICE_PACKAGE_NAME;
+        serviceInfo.permission = Manifest.permission.BIND_TV_REMOTE_SERVICE;
+
+        return serviceInfo;
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index e501452..48a583c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -39,6 +39,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -253,6 +254,30 @@
     }
 
     @Test
+    public void testOverrideConfigSize() {
+        removeGlobalMinSizeRestriction();
+        final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        final Task task = stack.getTopMostTask();
+        WindowContainerTransaction t = new WindowContainerTransaction();
+        t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+        mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+        final int origScreenWDp = task.getConfiguration().screenHeightDp;
+        final int origScreenHDp = task.getConfiguration().screenHeightDp;
+        t = new WindowContainerTransaction();
+        // verify that setting config overrides on parent restricts children.
+        t.setScreenSizeDp(stack.mRemoteToken, origScreenWDp, origScreenHDp);
+        t.setBounds(task.mRemoteToken, new Rect(10, 10, 150, 200));
+        mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+        assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
+        t = new WindowContainerTransaction();
+        t.setScreenSizeDp(stack.mRemoteToken, Configuration.SCREEN_WIDTH_DP_UNDEFINED,
+                Configuration.SCREEN_HEIGHT_DP_UNDEFINED);
+        mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+        assertNotEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
+    }
+
+    @Test
     public void testCreateDeleteRootTasks() {
         RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
                 Display.DEFAULT_DISPLAY,
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 01abb26..558f4cd 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -19,6 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.hardware.radio.V1_1.EutranBands;
+import android.hardware.radio.V1_1.GeranBands;
+import android.hardware.radio.V1_5.AccessNetwork;
+import android.hardware.radio.V1_5.UtranBands;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -84,13 +88,13 @@
     public @interface RadioAccessNetworkType {}
 
     public static final class AccessNetworkType {
-        public static final int UNKNOWN = 0;
-        public static final int GERAN = 1;
-        public static final int UTRAN = 2;
-        public static final int EUTRAN = 3;
-        public static final int CDMA2000 = 4;
-        public static final int IWLAN = 5;
-        public static final int NGRAN = 6;
+        public static final int UNKNOWN = AccessNetwork.UNKNOWN;
+        public static final int GERAN = AccessNetwork.GERAN;
+        public static final int UTRAN = AccessNetwork.UTRAN;
+        public static final int EUTRAN = AccessNetwork.EUTRAN;
+        public static final int CDMA2000 = AccessNetwork.CDMA2000;
+        public static final int IWLAN = AccessNetwork.IWLAN;
+        public static final int NGRAN = AccessNetwork.NGRAN;
 
         /** @hide */
         private AccessNetworkType() {}
@@ -115,20 +119,20 @@
      * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
      */
     public static final class GeranBand {
-        public static final int BAND_T380 = 1;
-        public static final int BAND_T410 = 2;
-        public static final int BAND_450 = 3;
-        public static final int BAND_480 = 4;
-        public static final int BAND_710 = 5;
-        public static final int BAND_750 = 6;
-        public static final int BAND_T810 = 7;
-        public static final int BAND_850 = 8;
-        public static final int BAND_P900 = 9;
-        public static final int BAND_E900 = 10;
-        public static final int BAND_R900 = 11;
-        public static final int BAND_DCS1800 = 12;
-        public static final int BAND_PCS1900 = 13;
-        public static final int BAND_ER900 = 14;
+        public static final int BAND_T380 = GeranBands.BAND_T380;
+        public static final int BAND_T410 = GeranBands.BAND_T410;
+        public static final int BAND_450 = GeranBands.BAND_450;
+        public static final int BAND_480 = GeranBands.BAND_480;
+        public static final int BAND_710 = GeranBands.BAND_710;
+        public static final int BAND_750 = GeranBands.BAND_750;
+        public static final int BAND_T810 = GeranBands.BAND_T810;
+        public static final int BAND_850 = GeranBands.BAND_850;
+        public static final int BAND_P900 = GeranBands.BAND_P900;
+        public static final int BAND_E900 = GeranBands.BAND_E900;
+        public static final int BAND_R900 = GeranBands.BAND_R900;
+        public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800;
+        public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900;
+        public static final int BAND_ER900 = GeranBands.BAND_ER900;
 
         /** @hide */
         private GeranBand() {}
@@ -139,28 +143,28 @@
      * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
      */
     public static final class UtranBand {
-        public static final int BAND_1 = 1;
-        public static final int BAND_2 = 2;
-        public static final int BAND_3 = 3;
-        public static final int BAND_4 = 4;
-        public static final int BAND_5 = 5;
-        public static final int BAND_6 = 6;
-        public static final int BAND_7 = 7;
-        public static final int BAND_8 = 8;
-        public static final int BAND_9 = 9;
-        public static final int BAND_10 = 10;
-        public static final int BAND_11 = 11;
-        public static final int BAND_12 = 12;
-        public static final int BAND_13 = 13;
-        public static final int BAND_14 = 14;
+        public static final int BAND_1 = UtranBands.BAND_1;
+        public static final int BAND_2 = UtranBands.BAND_2;
+        public static final int BAND_3 = UtranBands.BAND_3;
+        public static final int BAND_4 = UtranBands.BAND_4;
+        public static final int BAND_5 = UtranBands.BAND_5;
+        public static final int BAND_6 = UtranBands.BAND_6;
+        public static final int BAND_7 = UtranBands.BAND_7;
+        public static final int BAND_8 = UtranBands.BAND_8;
+        public static final int BAND_9 = UtranBands.BAND_9;
+        public static final int BAND_10 = UtranBands.BAND_10;
+        public static final int BAND_11 = UtranBands.BAND_11;
+        public static final int BAND_12 = UtranBands.BAND_12;
+        public static final int BAND_13 = UtranBands.BAND_13;
+        public static final int BAND_14 = UtranBands.BAND_14;
         // band 15, 16, 17, 18 are reserved
-        public static final int BAND_19 = 19;
-        public static final int BAND_20 = 20;
-        public static final int BAND_21 = 21;
-        public static final int BAND_22 = 22;
+        public static final int BAND_19 = UtranBands.BAND_19;
+        public static final int BAND_20 = UtranBands.BAND_20;
+        public static final int BAND_21 = UtranBands.BAND_21;
+        public static final int BAND_22 = UtranBands.BAND_22;
         // band 23, 24 are reserved
-        public static final int BAND_25 = 25;
-        public static final int BAND_26 = 26;
+        public static final int BAND_25 = UtranBands.BAND_25;
+        public static final int BAND_26 = UtranBands.BAND_26;
 
         // Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2.
 
@@ -169,38 +173,38 @@
          * 1900 - 1920 MHz: Uplink and downlink transmission
          * 2010 - 2025 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_A = 101;
+        public static final int BAND_A = UtranBands.BAND_A;
 
         /**
          * Band B
          * 1850 - 1910 MHz: Uplink and downlink transmission
          * 1930 - 1990 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_B = 102;
+        public static final int BAND_B = UtranBands.BAND_B;
 
         /**
          * Band C
          * 1910 - 1930 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_C = 103;
+        public static final int BAND_C = UtranBands.BAND_C;
 
         /**
          * Band D
          * 2570 - 2620 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_D = 104;
+        public static final int BAND_D = UtranBands.BAND_D;
 
         /**
          * Band E
          * 2300—2400 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_E = 105;
+        public static final int BAND_E = UtranBands.BAND_E;
 
         /**
          * Band F
          * 1880 - 1920 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_F = 106;
+        public static final int BAND_F = UtranBands.BAND_F;
 
         /** @hide */
         private UtranBand() {}
@@ -211,54 +215,54 @@
      * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
      */
     public static final class EutranBand {
-        public static final int BAND_1 = 1;
-        public static final int BAND_2 = 2;
-        public static final int BAND_3 = 3;
-        public static final int BAND_4 = 4;
-        public static final int BAND_5 = 5;
-        public static final int BAND_6 = 6;
-        public static final int BAND_7 = 7;
-        public static final int BAND_8 = 8;
-        public static final int BAND_9 = 9;
-        public static final int BAND_10 = 10;
-        public static final int BAND_11 = 11;
-        public static final int BAND_12 = 12;
-        public static final int BAND_13 = 13;
-        public static final int BAND_14 = 14;
-        public static final int BAND_17 = 17;
-        public static final int BAND_18 = 18;
-        public static final int BAND_19 = 19;
-        public static final int BAND_20 = 20;
-        public static final int BAND_21 = 21;
-        public static final int BAND_22 = 22;
-        public static final int BAND_23 = 23;
-        public static final int BAND_24 = 24;
-        public static final int BAND_25 = 25;
-        public static final int BAND_26 = 26;
-        public static final int BAND_27 = 27;
-        public static final int BAND_28 = 28;
-        public static final int BAND_30 = 30;
-        public static final int BAND_31 = 31;
-        public static final int BAND_33 = 33;
-        public static final int BAND_34 = 34;
-        public static final int BAND_35 = 35;
-        public static final int BAND_36 = 36;
-        public static final int BAND_37 = 37;
-        public static final int BAND_38 = 38;
-        public static final int BAND_39 = 39;
-        public static final int BAND_40 = 40;
-        public static final int BAND_41 = 41;
-        public static final int BAND_42 = 42;
-        public static final int BAND_43 = 43;
-        public static final int BAND_44 = 44;
-        public static final int BAND_45 = 45;
-        public static final int BAND_46 = 46;
-        public static final int BAND_47 = 47;
-        public static final int BAND_48 = 48;
-        public static final int BAND_65 = 65;
-        public static final int BAND_66 = 66;
-        public static final int BAND_68 = 68;
-        public static final int BAND_70 = 70;
+        public static final int BAND_1 = EutranBands.BAND_1;
+        public static final int BAND_2 = EutranBands.BAND_2;
+        public static final int BAND_3 = EutranBands.BAND_3;
+        public static final int BAND_4 = EutranBands.BAND_4;
+        public static final int BAND_5 = EutranBands.BAND_5;
+        public static final int BAND_6 = EutranBands.BAND_6;
+        public static final int BAND_7 = EutranBands.BAND_7;
+        public static final int BAND_8 = EutranBands.BAND_8;
+        public static final int BAND_9 = EutranBands.BAND_9;
+        public static final int BAND_10 = EutranBands.BAND_10;
+        public static final int BAND_11 = EutranBands.BAND_11;
+        public static final int BAND_12 = EutranBands.BAND_12;
+        public static final int BAND_13 = EutranBands.BAND_13;
+        public static final int BAND_14 = EutranBands.BAND_14;
+        public static final int BAND_17 = EutranBands.BAND_17;
+        public static final int BAND_18 = EutranBands.BAND_18;
+        public static final int BAND_19 = EutranBands.BAND_19;
+        public static final int BAND_20 = EutranBands.BAND_20;
+        public static final int BAND_21 = EutranBands.BAND_21;
+        public static final int BAND_22 = EutranBands.BAND_22;
+        public static final int BAND_23 = EutranBands.BAND_23;
+        public static final int BAND_24 = EutranBands.BAND_24;
+        public static final int BAND_25 = EutranBands.BAND_25;
+        public static final int BAND_26 = EutranBands.BAND_26;
+        public static final int BAND_27 = EutranBands.BAND_27;
+        public static final int BAND_28 = EutranBands.BAND_28;
+        public static final int BAND_30 = EutranBands.BAND_30;
+        public static final int BAND_31 = EutranBands.BAND_31;
+        public static final int BAND_33 = EutranBands.BAND_33;
+        public static final int BAND_34 = EutranBands.BAND_34;
+        public static final int BAND_35 = EutranBands.BAND_35;
+        public static final int BAND_36 = EutranBands.BAND_36;
+        public static final int BAND_37 = EutranBands.BAND_37;
+        public static final int BAND_38 = EutranBands.BAND_38;
+        public static final int BAND_39 = EutranBands.BAND_39;
+        public static final int BAND_40 = EutranBands.BAND_40;
+        public static final int BAND_41 = EutranBands.BAND_41;
+        public static final int BAND_42 = EutranBands.BAND_42;
+        public static final int BAND_43 = EutranBands.BAND_43;
+        public static final int BAND_44 = EutranBands.BAND_44;
+        public static final int BAND_45 = EutranBands.BAND_45;
+        public static final int BAND_46 = EutranBands.BAND_46;
+        public static final int BAND_47 = EutranBands.BAND_47;
+        public static final int BAND_48 = EutranBands.BAND_48;
+        public static final int BAND_65 = EutranBands.BAND_65;
+        public static final int BAND_66 = EutranBands.BAND_66;
+        public static final int BAND_68 = EutranBands.BAND_68;
+        public static final int BAND_70 = EutranBands.BAND_70;
 
         /** @hide */
         private EutranBand() {};
@@ -304,51 +308,51 @@
      */
     public static final class NgranBands {
         /** FR1 bands */
-        public static final int BAND_1 = 1;
-        public static final int BAND_2 = 2;
-        public static final int BAND_3 = 3;
-        public static final int BAND_5 = 5;
-        public static final int BAND_7 = 7;
-        public static final int BAND_8 = 8;
-        public static final int BAND_12 = 12;
-        public static final int BAND_14 = 14;
-        public static final int BAND_18 = 18;
-        public static final int BAND_20 = 20;
-        public static final int BAND_25 = 25;
-        public static final int BAND_28 = 28;
-        public static final int BAND_29 = 29;
-        public static final int BAND_30 = 30;
-        public static final int BAND_34 = 34;
-        public static final int BAND_38 = 38;
-        public static final int BAND_39 = 39;
-        public static final int BAND_40 = 40;
-        public static final int BAND_41 = 41;
-        public static final int BAND_48 = 48;
-        public static final int BAND_50 = 50;
-        public static final int BAND_51 = 51;
-        public static final int BAND_65 = 65;
-        public static final int BAND_66 = 66;
-        public static final int BAND_70 = 70;
-        public static final int BAND_71 = 71;
-        public static final int BAND_74 = 74;
-        public static final int BAND_75 = 75;
-        public static final int BAND_76 = 76;
-        public static final int BAND_77 = 77;
-        public static final int BAND_78 = 78;
-        public static final int BAND_79 = 79;
-        public static final int BAND_80 = 80;
-        public static final int BAND_81 = 81;
-        public static final int BAND_82 = 82;
-        public static final int BAND_83 = 83;
-        public static final int BAND_84 = 84;
-        public static final int BAND_86 = 86;
-        public static final int BAND_90 = 90;
+        public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
+        public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
+        public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
+        public static final int BAND_5 = android.hardware.radio.V1_5.NgranBands.BAND_5;
+        public static final int BAND_7 = android.hardware.radio.V1_5.NgranBands.BAND_7;
+        public static final int BAND_8 = android.hardware.radio.V1_5.NgranBands.BAND_8;
+        public static final int BAND_12 = android.hardware.radio.V1_5.NgranBands.BAND_12;
+        public static final int BAND_14 = android.hardware.radio.V1_5.NgranBands.BAND_14;
+        public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18;
+        public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20;
+        public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25;
+        public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28;
+        public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29;
+        public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30;
+        public static final int BAND_34 = android.hardware.radio.V1_5.NgranBands.BAND_34;
+        public static final int BAND_38 = android.hardware.radio.V1_5.NgranBands.BAND_38;
+        public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39;
+        public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40;
+        public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41;
+        public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48;
+        public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50;
+        public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51;
+        public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65;
+        public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66;
+        public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70;
+        public static final int BAND_71 = android.hardware.radio.V1_5.NgranBands.BAND_71;
+        public static final int BAND_74 = android.hardware.radio.V1_5.NgranBands.BAND_74;
+        public static final int BAND_75 = android.hardware.radio.V1_5.NgranBands.BAND_75;
+        public static final int BAND_76 = android.hardware.radio.V1_5.NgranBands.BAND_76;
+        public static final int BAND_77 = android.hardware.radio.V1_5.NgranBands.BAND_77;
+        public static final int BAND_78 = android.hardware.radio.V1_5.NgranBands.BAND_78;
+        public static final int BAND_79 = android.hardware.radio.V1_5.NgranBands.BAND_79;
+        public static final int BAND_80 = android.hardware.radio.V1_5.NgranBands.BAND_80;
+        public static final int BAND_81 = android.hardware.radio.V1_5.NgranBands.BAND_81;
+        public static final int BAND_82 = android.hardware.radio.V1_5.NgranBands.BAND_82;
+        public static final int BAND_83 = android.hardware.radio.V1_5.NgranBands.BAND_83;
+        public static final int BAND_84 = android.hardware.radio.V1_5.NgranBands.BAND_84;
+        public static final int BAND_86 = android.hardware.radio.V1_5.NgranBands.BAND_86;
+        public static final int BAND_90 = android.hardware.radio.V1_5.NgranBands.BAND_90;
 
         /** FR2 bands */
-        public static final int BAND_257 = 257;
-        public static final int BAND_258 = 258;
-        public static final int BAND_260 = 260;
-        public static final int BAND_261 = 261;
+        public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
+        public static final int BAND_258 = android.hardware.radio.V1_5.NgranBands.BAND_258;
+        public static final int BAND_260 = android.hardware.radio.V1_5.NgranBands.BAND_260;
+        public static final int BAND_261 = android.hardware.radio.V1_5.NgranBands.BAND_261;
 
         /**
          * NR Bands
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index d504b38..fe75266 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -74,17 +74,17 @@
             "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
 
     /**
-     * An extra key corresponding to a String value which contains the carrier specific title to be
-     * displayed as part of the message shown to the user when there is an error registering for
-     * WiFi calling.
+     * An extra key corresponding to a {@link CharSequence} value which contains the carrier
+     * specific title to be displayed as part of the message shown to the user when there is an
+     * error registering for WiFi calling.
      */
     public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE =
             "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
 
     /**
-     * An extra key corresponding to a String value which contains the carrier specific message to
-     * be displayed as part of the message shown to the user when there is an error registering for
-     * WiFi calling.
+     * An extra key corresponding to a {@link CharSequence} value which contains the carrier
+     * specific message to  be displayed as part of the message shown to the user when there is an
+     * error registering for WiFi calling.
      */
     public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE =
             "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 08614b9..9b1baef 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1411,6 +1411,7 @@
             DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
             if (dsri != null) {
                 dsri.setIsUsingCarrierAggregation(ca);
+                addNetworkRegistrationInfo(nri);
             }
         }
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 27bbe68..40def40 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -333,21 +333,6 @@
     };
 
     /** @hide */
-    @IntDef(prefix = {"MODEM_COUNT_"},
-            value = {
-                    MODEM_COUNT_NO_MODEM,
-                    MODEM_COUNT_SINGLE_MODEM,
-                    MODEM_COUNT_DUAL_MODEM,
-                    MODEM_COUNT_TRI_MODEM
-            })
-    public @interface ModemCount {}
-
-    public static final int MODEM_COUNT_NO_MODEM     = 0;
-    public static final int MODEM_COUNT_SINGLE_MODEM = 1;
-    public static final int MODEM_COUNT_DUAL_MODEM   = 2;
-    public static final int MODEM_COUNT_TRI_MODEM    = 3;
-
-    /** @hide */
     @UnsupportedAppUsage
     public TelephonyManager(Context context) {
       this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
@@ -465,22 +450,22 @@
      * Returns 2 for Dual standby mode (Dual SIM functionality).
      * Returns 3 for Tri standby mode (Tri SIM functionality).
      */
-    public @ModemCount int getActiveModemCount() {
+    public int getActiveModemCount() {
         int modemCount = 1;
         switch (getMultiSimConfiguration()) {
             case UNKNOWN:
-                modemCount = MODEM_COUNT_SINGLE_MODEM;
+                modemCount = 1;
                 // check for voice and data support, 0 if not supported
                 if (!isVoiceCapable() && !isSmsCapable() && !isDataCapable()) {
-                    modemCount = MODEM_COUNT_NO_MODEM;
+                    modemCount = 0;
                 }
                 break;
             case DSDS:
             case DSDA:
-                modemCount = MODEM_COUNT_DUAL_MODEM;
+                modemCount = 2;
                 break;
             case TSTS:
-                modemCount = MODEM_COUNT_TRI_MODEM;
+                modemCount = 3;
                 break;
         }
         return modemCount;
@@ -493,7 +478,7 @@
      * dual-SIM capable device operating in single SIM mode (only one logical modem is turned on),
      * {@link #getActiveModemCount} returns 1 while this API returns 2.
      */
-    public @ModemCount int getSupportedModemCount() {
+    public int getSupportedModemCount() {
         return TelephonyProperties.max_active_modems().orElse(getActiveModemCount());
     }
 
@@ -12669,7 +12654,8 @@
      * {@hide}
      */
     @SystemApi
-    public boolean isCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean matchesCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
             @Nullable String mvnoMatchData) {
         try {
             if (!mccmnc.equals(getSimOperator())) {
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 61f3dba..4ecca2d 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -78,13 +78,12 @@
             return false;
         }
         String res = mTestDevice.executeShellCommand("kill -s SIGUSR1 " + pid).trim();
-        assertTrue("kill SIGUSR1: " + res, res.length() == 0);
-        return true;
+        return res.length() == 0;
     }
 
     @Test
     public void testSystemServerProfile() throws Exception {
-        final int numIterations = 20;
+        final int numIterations = 30;
         String res;
         // Set properties and wait for them to be readable.
         for (int i = 1; i <= numIterations; ++i) {
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 339df93..475305e 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -51,7 +51,7 @@
     }
 
     @DataClass.Generated.Member
-    public HierrarchicalDataClassBase setBaseData(int value) {
+    public HierrarchicalDataClassBase setBaseData( int value) {
         mBaseData = value;
         return this;
     }
@@ -98,8 +98,8 @@
     };
 
     @DataClass.Generated(
-            time = 1574122837821L,
-            codegenVersion = "1.0.14",
+            time = 1582685650576L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
             inputSignatures = "private  int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index 69e06b2..150b324 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -120,8 +120,8 @@
     };
 
     @DataClass.Generated(
-            time = 1574122838768L,
-            codegenVersion = "1.0.14",
+            time = 1582685651560L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
             inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index ca128be..3087156 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -355,7 +355,7 @@
         }
 
         @DataClass.Generated.Member
-        public @NonNull Builder setNullableBoolean(@SuppressWarnings({ "WeakerAccess" }) @Nullable Boolean value) {
+        public @NonNull Builder setNullableBoolean(@SuppressWarnings({ "WeakerAccess" }) @NonNull Boolean value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x80;
             mNullableBoolean = value;
@@ -412,8 +412,8 @@
     }
 
     @DataClass.Generated(
-            time = 1574122836960L,
-            codegenVersion = "1.0.14",
+            time = 1582685649678L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
             inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index c850bf8..8d421bf 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -512,7 +512,7 @@
             @Nullable LinkAddress[] linkAddresses5,
             @StringRes int stringRes,
             @android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
-            @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] coords) {
+            @Size(2) @NonNull @FloatRange(from = 0f) float[] coords) {
         this.mNum = num;
         this.mNum2 = num2;
         this.mNum4 = num4;
@@ -790,7 +790,7 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @DataClass.Generated.Member
-    public @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] getCoords() {
+    public @Size(2) @NonNull @FloatRange(from = 0f) float[] getCoords() {
         return mCoords;
     }
 
@@ -820,7 +820,7 @@
      * pieces in multiple places for each field.
      */
     @DataClass.Generated.Member
-    public SampleDataClass setNum(int value) {
+    public SampleDataClass setNum( int value) {
         mNum = value;
         return this;
     }
@@ -832,7 +832,7 @@
      * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
      */
     @DataClass.Generated.Member
-    public SampleDataClass setNum2(int value) {
+    public SampleDataClass setNum2( int value) {
         mNum2 = value;
         return this;
     }
@@ -846,7 +846,7 @@
      * @hide
      */
     @DataClass.Generated.Member
-    public SampleDataClass setNum4(int value) {
+    public SampleDataClass setNum4( int value) {
         mNum4 = value;
         return this;
     }
@@ -855,7 +855,7 @@
      * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
      */
     @DataClass.Generated.Member
-    public SampleDataClass setName(@Nullable String value) {
+    public SampleDataClass setName(@NonNull String value) {
         mName = value;
         return this;
     }
@@ -892,7 +892,7 @@
      * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
      */
     @DataClass.Generated.Member
-    public SampleDataClass setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
+    public SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
         mOtherParcelable = value;
         return this;
     }
@@ -957,7 +957,7 @@
      * @see Builder#setLinkAddresses4(LinkAddress...)
      */
     @DataClass.Generated.Member
-    public SampleDataClass setLinkAddresses4(@Nullable LinkAddress... value) {
+    public SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) {
         mLinkAddresses4 = value;
         return this;
     }
@@ -1070,7 +1070,7 @@
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @DataClass.Generated.Member
-    public SampleDataClass setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
+    public SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
         mCoords = value;
         AnnotationValidations.validate(
                 Size.class, null, mCoords.length,
@@ -1451,7 +1451,7 @@
         private @Nullable LinkAddress[] mLinkAddresses5;
         private @StringRes int mStringRes;
         private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
-        private @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] mCoords;
+        private @Size(2) @NonNull @FloatRange(from = 0f) float[] mCoords;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -1549,7 +1549,7 @@
          * {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setName(@Nullable String value) {
+        public @NonNull Builder setName(@NonNull String value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x8;
             mName = value;
@@ -1588,7 +1588,7 @@
          * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
+        public @NonNull Builder setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x40;
             mOtherParcelable = value;
@@ -1674,7 +1674,7 @@
          * @see Builder#setLinkAddresses4(LinkAddress...)
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setLinkAddresses4(@Nullable LinkAddress... value) {
+        public @NonNull Builder setLinkAddresses4(@NonNull LinkAddress... value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x800;
             mLinkAddresses4 = value;
@@ -1733,7 +1733,7 @@
          * Final fields suppress generating a setter (when setters are requested).
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setLinkAddresses5(@Nullable LinkAddress... value) {
+        public @NonNull Builder setLinkAddresses5(@NonNull LinkAddress... value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x10000;
             mLinkAddresses5 = value;
@@ -1785,7 +1785,7 @@
          * @see AnnotationValidations#validate(Class, Size, int, String, int)
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
+        public @NonNull Builder setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x80000;
             mCoords = value;
@@ -1872,8 +1872,8 @@
     }
 
     @DataClass.Generated(
-            time = 1574122835009L,
-            codegenVersion = "1.0.14",
+            time = 1582685647656L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
             inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 2de848c..d9fe1fd 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -253,8 +253,8 @@
     }
 
     @DataClass.Generated(
-            time = 1574122835982L,
-            codegenVersion = "1.0.14",
+            time = 1582685648622L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
             inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nprivate static  java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate  void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index 0deffe4..f98d7b0 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@
 
 
 
-        // Code below generated by codegen v1.0.14.
+        // Code below generated by codegen v1.0.15.
         //
         // DO NOT MODIFY!
         // CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@
         };
 
         @DataClass.Generated(
-                time = 1574122840588L,
-                codegenVersion = "1.0.14",
+                time = 1582685653406L,
+                codegenVersion = "1.0.15",
                 sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
                 inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
         @Deprecated
@@ -160,7 +160,7 @@
 
 
 
-            // Code below generated by codegen v1.0.14.
+            // Code below generated by codegen v1.0.15.
             //
             // DO NOT MODIFY!
             // CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@
             };
 
             @DataClass.Generated(
-                    time = 1574122840597L,
-                    codegenVersion = "1.0.14",
+                    time = 1582685653415L,
+                    codegenVersion = "1.0.15",
                     sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
                     inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
             @Deprecated
@@ -274,7 +274,7 @@
 
 
 
-        // Code below generated by codegen v1.0.14.
+        // Code below generated by codegen v1.0.15.
         //
         // DO NOT MODIFY!
         // CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@
         };
 
         @DataClass.Generated(
-                time = 1574122840608L,
-                codegenVersion = "1.0.14",
+                time = 1582685653420L,
+                codegenVersion = "1.0.15",
                 sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
                 inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
         @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 712722b..6b4fc2f 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -51,7 +51,7 @@
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -65,8 +65,8 @@
 
 
     @DataClass.Generated(
-            time = 1574122839646L,
-            codegenVersion = "1.0.14",
+            time = 1582685652436L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
             inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
     @Deprecated
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index c7c80ba..b90e1bb 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -100,7 +100,7 @@
             ?: emptyMap()
 
     val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, UnsupportedAppUsage,
-            DataClassSuppressConstDefs)
+            DataClassSuppressConstDefs, MaySetToNull, Each, DataClass)
     val knownNonValidationAnnotations = internalAnnotations + Each + Nullable
 
     /**
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
index ebfbbd8..02ebaef 100644
--- a/tools/codegen/src/com/android/codegen/FieldInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -147,9 +147,19 @@
     val sParcelling by lazy { customParcellingClass?.let { "sParcellingFor$NameUpperCamel" } }
 
     val SetterParamType = if (isArray) "$FieldInnerType..." else Type
-    val annotatedTypeForSetterParam by lazy {
-        (annotationsNoInternal + SetterParamType).joinToString(" ")
+    val annotationsForSetterParam by lazy {
+        buildList<String> {
+            addAll(annotationsNoInternal)
+            classPrinter {
+                if ("@$Nullable" in annotations
+                        && "@$MaySetToNull" !in annotations) {
+                    remove("@$Nullable")
+                    add("@$NonNull")
+                }
+            }
+        }.joinToString(" ")
     }
+    val annotatedTypeForSetterParam by lazy { "$annotationsForSetterParam $SetterParamType" }
 
     // Utilities
 
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 8fe243f..5a96cf1 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -315,7 +315,7 @@
         generateBuilderMethod(
                 name = setterName,
                 defVisibility = visibility,
-                paramAnnotations = annotationsNoInternal.joinToString(" "),
+                paramAnnotations = annotationsForSetterParam,
                 paramTypes = listOf(SetterParamType),
                 genJavadoc = { generateFieldJavadoc() }) {
             +"checkNotUsed();"
diff --git a/tools/codegen/src/com/android/codegen/ImportsProvider.kt b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
index c830aaa..27dd958 100644
--- a/tools/codegen/src/com/android/codegen/ImportsProvider.kt
+++ b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
@@ -39,6 +39,7 @@
     val ParcelWith: String get() { return classRef("com.android.internal.util.DataClass.ParcelWith") }
     val PluralOf: String get() { return classRef("com.android.internal.util.DataClass.PluralOf") }
     val Each: String get() { return classRef("com.android.internal.util.DataClass.Each") }
+    val MaySetToNull: String get() { return classRef("com.android.internal.util.DataClass.MaySetToNull") }
     val DataClassGenerated: String get() { return classRef("com.android.internal.util.DataClass.Generated") }
     val DataClassSuppressConstDefs: String get() { return classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
     val DataClassSuppress: String get() { return classRef("com.android.internal.util.DataClass.Suppress") }
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 74c86f4..6f740cd6 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.14"
+const val CODEGEN_VERSION = "1.0.15"
 
 const val CANONICAL_BUILDER_CLASS = "Builder"
 const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 843e820..cbf6fe8 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -26,11 +26,9 @@
         "java_writer_q.cpp",
         "main.cpp",
         "native_writer.cpp",
-        "native_writer_q.cpp",
         "utils.cpp",
     ],
     cflags: [
-        //"-DSTATS_SCHEMA_LEGACY",
         "-Wall",
         "-Werror",
     ],
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 8bccd71..66c4b14 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -53,8 +53,7 @@
         uidField(that.uidField),
         whitelisted(that.whitelisted),
         binaryFields(that.binaryFields),
-        hasModule(that.hasModule),
-        moduleName(that.moduleName) {}
+        moduleNames(that.moduleNames) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -237,6 +236,16 @@
         errorCount++;
         continue;
     }
+
+    if (field->is_repeated() &&
+        !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
+        print_error(field,
+                    "Repeated fields are not supported in atoms. Please make field %s not "
+                    "repeated.\n",
+                    field->name().c_str());
+        errorCount++;
+        continue;
+    }
   }
 
   // Check that if there's an attribution chain, it's at position 1.
@@ -432,9 +441,9 @@
         atomDecl.whitelisted = true;
     }
 
-    if (atomField->options().HasExtension(os::statsd::module)) {
-        atomDecl.hasModule = true;
-        atomDecl.moduleName = atomField->options().GetExtension(os::statsd::module);
+    for (int j = 0; j < atomField->options().ExtensionSize(os::statsd::module); ++j) {
+        const string moduleName = atomField->options().GetExtension(os::statsd::module, j);
+        atomDecl.moduleNames.insert(moduleName);
     }
 
     vector<java_type_t> signature;
@@ -443,36 +452,15 @@
         errorCount++;
     }
 
-    // Add the signature if does not already exist.
-    auto signature_to_modules_it = atoms->signatures_to_modules.find(signature);
-    if (signature_to_modules_it == atoms->signatures_to_modules.end()) {
-        set<string> modules;
-        if (atomDecl.hasModule) {
-            modules.insert(atomDecl.moduleName);
-        }
-        atoms->signatures_to_modules[signature] = modules;
-    } else {
-        if (atomDecl.hasModule) {
-            signature_to_modules_it->second.insert(atomDecl.moduleName);
-        }
-    }
+    atoms->signatures_to_modules[signature].insert(
+            atomDecl.moduleNames.begin(), atomDecl.moduleNames.end());
     atoms->decls.insert(atomDecl);
 
     AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
     vector<java_type_t> nonChainedSignature;
     if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
-        auto it = atoms->non_chained_signatures_to_modules.find(nonChainedSignature);
-        if (it == atoms->non_chained_signatures_to_modules.end()) {
-            set<string> modules_non_chained;
-            if (atomDecl.hasModule) {
-                modules_non_chained.insert(atomDecl.moduleName);
-            }
-            atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained;
-        } else {
-            if (atomDecl.hasModule) {
-                it->second.insert(atomDecl.moduleName);
-            }
-        }
+        atoms->non_chained_signatures_to_modules[nonChainedSignature].insert(
+            atomDecl.moduleNames.begin(), atomDecl.moduleNames.end());
         atoms->non_chained_decls.insert(nonChainedAtomDecl);
     }
 
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 65d8e3e..ace85e0 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -98,8 +98,7 @@
 
     vector<int> binaryFields;
 
-    bool hasModule = false;
-    string moduleName;
+    set<string> moduleNames;
 
     AtomDecl();
     AtomDecl(const AtomDecl& that);
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 984c929..58f13a4 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -58,19 +58,25 @@
 }
 
 static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
-    std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
-                                                 "audio_state_changed",
-                                                 "call_state_changed",
-                                                 "phone_signal_strength_changed",
-                                                 "mobile_bytes_transfer_by_fg_bg",
-                                                 "mobile_bytes_transfer"};
+    std::set<string> kTruncatingAtomNames = {
+            "mobile_radio_power_state_changed",
+            "audio_state_changed",
+            "call_state_changed",
+            "phone_signal_strength_changed",
+            "mobile_bytes_transfer_by_fg_bg",
+            "mobile_bytes_transfer"
+    };
     fprintf(out,
             "const std::set<int> "
             "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
-    for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin();
-         blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) {
-            fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str());
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) {
+            const string constant = make_constant_name(atom->name);
+            fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
+        }
     }
+
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
@@ -81,8 +87,8 @@
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
              field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                string constant = make_constant_name(atom->name);
-                fprintf(out, " %s,\n", constant.c_str());
+                const string constant = make_constant_name(atom->name);
+                fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
                 break;
             }
         }
@@ -96,8 +102,8 @@
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
          atom != atoms.decls.end(); atom++) {
         if (atom->whitelisted) {
-            string constant = make_constant_name(atom->name);
-            fprintf(out, " %s,\n", constant.c_str());
+            const string constant = make_constant_name(atom->name);
+            fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
         }
     }
 
@@ -105,7 +111,7 @@
     fprintf(out, "\n");
 
     fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
-    fprintf(out, "  std::map<int, int> uidField;\n");
+    fprintf(out, "    std::map<int, int> uidField;\n");
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
          atom != atoms.decls.end(); atom++) {
         if (atom->uidField == 0) {
@@ -115,8 +121,8 @@
                 "\n    // Adding uid field for atom "
                 "(%d)%s\n",
                 atom->code, atom->name.c_str());
-        fprintf(out, "    uidField[static_cast<int>(%s)] = %d;\n",
-                make_constant_name(atom->name).c_str(), atom->uidField);
+        fprintf(out, "    uidField[%d /* %s */] = %d;\n",
+                atom->code, make_constant_name(atom->name).c_str(), atom->uidField);
     }
 
     fprintf(out, "    return uidField;\n");
@@ -140,8 +146,8 @@
                 "\n    // Adding primary and exclusive fields for atom "
                 "(%d)%s\n",
                 atom->code, atom->name.c_str());
-        fprintf(out, "    opt = &(options[static_cast<int>(%s)]);\n",
-                make_constant_name(atom->name).c_str());
+        fprintf(out, "    opt = &(options[%d /* %s */]);\n",
+                atom->code, make_constant_name(atom->name).c_str());
         fprintf(out, "    opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
         for (const auto& field : atom->primaryFields) {
             fprintf(out, "    opt->primaryFields.push_back(%d);\n", field);
@@ -185,8 +191,8 @@
                 atom->code, atom->name.c_str());
 
         for (const auto& field : atom->binaryFields) {
-            fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
-                    make_constant_name(atom->name).c_str(), field);
+            fprintf(out, "    options[%d /* %s */].push_back(%d);\n",
+                    atom->code, make_constant_name(atom->name).c_str(), field);
         }
     }
 
@@ -222,12 +228,11 @@
 }
 
 int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr,
-        const string& importHeader, const string& statslogHeader) {
+        const string& importHeader) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
     fprintf(out, "#include <%s>\n", importHeader.c_str());
-    fprintf(out, "#include <%s>\n", statslogHeader.c_str());
     fprintf(out, "\n");
 
     write_namespace(out, namespaceStr);
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
index 12ac862..d04e65a 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.h
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -27,7 +27,7 @@
 using namespace std;
 
 int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
-        const string& importHeader, const string& statslogHeader);
+        const string& importHeader);
 
 int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
 
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index c29936b..209d511 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -59,9 +59,6 @@
         }
 
         // Print method signature.
-        if (DEFAULT_MODULE_NAME == moduleName) {
-            fprintf(out, "    /** @hide */\n");
-        }
         fprintf(out, "    public static void write(int code");
         vector<java_type_t> signature = signature_to_modules_it->first;
         int argIndex = 1;
@@ -273,9 +270,6 @@
     fprintf(out, "\n");
     fprintf(out, "/**\n");
     fprintf(out, " * Utility class for logging statistics events.\n");
-    if (DEFAULT_MODULE_NAME == moduleName) {
-        fprintf(out, " * @hide\n");
-    }
     fprintf(out, " */\n");
     fprintf(out, "public class %s {\n", javaClass.c_str());
 
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index 12c050d..8f2112a 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -609,69 +609,5 @@
     return errors;
 }
 
-#if defined(STATS_SCHEMA_LEGACY)
-static void write_java_method(
-        FILE* out,
-        const string& method_name,
-        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
-        const AtomDecl &attributionDecl) {
-
-    for (auto signature_to_modules_it = signatures_to_modules.begin();
-            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
-        vector<java_type_t> signature = signature_to_modules_it->first;
-        fprintf(out, "    /** @hide */\n");
-        fprintf(out, "    public static native int %s(int code", method_name.c_str());
-        int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-            arg != signature.end(); arg++) {
-            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, ", %s[] %s",
-                        java_type_name(chainField.javaType), chainField.name.c_str());
-                }
-            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                fprintf(out, ", android.util.SparseArray<Object> valueMap");
-            } else {
-                fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
-            }
-            argIndex++;
-        }
-        fprintf(out, ");\n");
-        fprintf(out, "\n");
-    }
-}
-
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-                           const bool supportWorkSource) {
-    // Print prelude
-    fprintf(out, "// This file is autogenerated\n");
-    fprintf(out, "\n");
-    fprintf(out, "package android.util;\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "/**\n");
-    fprintf(out, " * API For logging statistics events.\n");
-    fprintf(out, " * @hide\n");
-    fprintf(out, " */\n");
-    fprintf(out, "public class StatsLogInternal {\n");
-    write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME);
-
-    write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME);
-
-    // Print write methods
-    fprintf(out, "    // Write methods\n");
-    write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
-    write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
-            attributionDecl);
-    if (supportWorkSource) {
-        write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
-    }
-
-    fprintf(out, "}\n");
-
-    return 0;
-}
-#endif
-
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 7d734df..6ccb225 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -49,9 +49,5 @@
         const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
         const string& javaPackage, const bool supportWorkSource);
 
-#if defined(STATS_SCHEMA_LEGACY)
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-                           const bool supportWorkSource);
-#endif
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index ddbf22c..e9723a1 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1,10 +1,7 @@
 
-
 #include "Collation.h"
 #include "atoms_info_writer.h"
-#if !defined(STATS_SCHEMA_LEGACY)
 #include "java_writer.h"
-#endif
 #include "java_writer_q.h"
 #include "native_writer.h"
 #include "utils.h"
@@ -28,463 +25,6 @@
 
 using android::os::statsd::Atom;
 
-// Hide the JNI write helpers that are not used in the new schema.
-// TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is
-// complete.
-#if defined(STATS_SCHEMA_LEGACY)
-// JNI helpers.
-static const char*
-jni_type_name(java_type_t type)
-{
-    switch (type) {
-        case JAVA_TYPE_BOOLEAN:
-            return "jboolean";
-        case JAVA_TYPE_INT:
-        case JAVA_TYPE_ENUM:
-            return "jint";
-        case JAVA_TYPE_LONG:
-            return "jlong";
-        case JAVA_TYPE_FLOAT:
-            return "jfloat";
-        case JAVA_TYPE_DOUBLE:
-            return "jdouble";
-        case JAVA_TYPE_STRING:
-            return "jstring";
-        case JAVA_TYPE_BYTE_ARRAY:
-            return "jbyteArray";
-        default:
-            return "UNKNOWN";
-    }
-}
-
-static const char*
-jni_array_type_name(java_type_t type)
-{
-    switch (type) {
-        case JAVA_TYPE_INT:
-            return "jintArray";
-        case JAVA_TYPE_FLOAT:
-            return "jfloatArray";
-        case JAVA_TYPE_STRING:
-            return "jobjectArray";
-        default:
-            return "UNKNOWN";
-    }
-}
-
-static string
-jni_function_name(const string& method_name, const vector<java_type_t>& signature)
-{
-    string result("StatsLog_" + method_name);
-    for (vector<java_type_t>::const_iterator arg = signature.begin();
-        arg != signature.end(); arg++) {
-        switch (*arg) {
-            case JAVA_TYPE_BOOLEAN:
-                result += "_boolean";
-                break;
-            case JAVA_TYPE_INT:
-            case JAVA_TYPE_ENUM:
-                result += "_int";
-                break;
-            case JAVA_TYPE_LONG:
-                result += "_long";
-                break;
-            case JAVA_TYPE_FLOAT:
-                result += "_float";
-                break;
-            case JAVA_TYPE_DOUBLE:
-                result += "_double";
-                break;
-            case JAVA_TYPE_STRING:
-                result += "_String";
-                break;
-            case JAVA_TYPE_ATTRIBUTION_CHAIN:
-              result += "_AttributionChain";
-              break;
-            case JAVA_TYPE_KEY_VALUE_PAIR:
-              result += "_KeyValuePairs";
-              break;
-            case JAVA_TYPE_BYTE_ARRAY:
-                result += "_bytes";
-                break;
-            default:
-                result += "_UNKNOWN";
-                break;
-        }
-    }
-    return result;
-}
-
-static const char*
-java_type_signature(java_type_t type)
-{
-    switch (type) {
-        case JAVA_TYPE_BOOLEAN:
-            return "Z";
-        case JAVA_TYPE_INT:
-        case JAVA_TYPE_ENUM:
-            return "I";
-        case JAVA_TYPE_LONG:
-            return "J";
-        case JAVA_TYPE_FLOAT:
-            return "F";
-        case JAVA_TYPE_DOUBLE:
-            return "D";
-        case JAVA_TYPE_STRING:
-            return "Ljava/lang/String;";
-        case JAVA_TYPE_BYTE_ARRAY:
-            return "[B";
-        default:
-            return "UNKNOWN";
-    }
-}
-
-static string
-jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
-{
-    string result("(I");
-    for (vector<java_type_t>::const_iterator arg = signature.begin();
-        arg != signature.end(); arg++) {
-        if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            for (auto chainField : attributionDecl.fields) {
-                result += "[";
-                result += java_type_signature(chainField.javaType);
-            }
-        } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-            result += "Landroid/util/SparseArray;";
-        } else {
-            result += java_type_signature(*arg);
-        }
-    }
-    result += ")I";
-    return result;
-}
-
-static void write_key_value_map_jni(FILE* out) {
-   fprintf(out, "    std::map<int, int32_t> int32_t_map;\n");
-   fprintf(out, "    std::map<int, int64_t> int64_t_map;\n");
-   fprintf(out, "    std::map<int, float> float_map;\n");
-   fprintf(out, "    std::map<int, char const*> string_map;\n\n");
-
-   fprintf(out, "    jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
-
-   fprintf(out, "    jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
-   fprintf(out, "    jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
-   fprintf(out, "    jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
-
-
-   fprintf(out, "    std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
-
-   fprintf(out, "    jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
-   fprintf(out, "    jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
-   fprintf(out, "    jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
-   fprintf(out, "    jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
-   fprintf(out, "    jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
-   fprintf(out, "    jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
-   fprintf(out, "    jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
-
-   fprintf(out, "    jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
-   fprintf(out, "    for(int i = 0; i < jsize; i++) {\n");
-   fprintf(out, "        jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
-   fprintf(out, "        jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
-   fprintf(out, "        if (jvalue_obj == NULL) { continue; }\n");
-   fprintf(out, "        if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
-   fprintf(out, "            int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
-   fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
-   fprintf(out, "            int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
-   fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
-   fprintf(out, "            float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
-   fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
-   fprintf(out, "            std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
-   fprintf(out, "            if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
-   fprintf(out, "            scoped_ufs.push_back(std::move(utf));\n");
-   fprintf(out, "        }\n");
-   fprintf(out, "    }\n");
-}
-
-static int
-write_stats_log_jni_method(FILE* out, const string& java_method_name, const string& cpp_method_name,
-        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
-        const AtomDecl &attributionDecl) {
-    // Print write methods
-    for (auto signature_to_modules_it = signatures_to_modules.begin();
-            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
-        vector<java_type_t> signature = signature_to_modules_it->first;
-        int argIndex;
-
-        fprintf(out, "static int\n");
-        fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
-                jni_function_name(java_method_name, signature).c_str());
-        argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
-            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
-                        chainField.name.c_str());
-                }
-            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                fprintf(out, ", jobject value_map");
-            } else {
-                fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
-            }
-            argIndex++;
-        }
-        fprintf(out, ")\n");
-
-        fprintf(out, "{\n");
-
-        // Prepare strings
-        argIndex = 1;
-        bool hadStringOrChain = false;
-        bool isKeyValuePairAtom = false;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
-            if (*arg == JAVA_TYPE_STRING) {
-                hadStringOrChain = true;
-                fprintf(out, "    const char* str%d;\n", argIndex);
-                fprintf(out, "    if (arg%d != NULL) {\n", argIndex);
-                fprintf(out, "        str%d = env->GetStringUTFChars(arg%d, NULL);\n",
-                        argIndex, argIndex);
-                fprintf(out, "    } else {\n");
-                fprintf(out, "        str%d = NULL;\n", argIndex);
-                fprintf(out, "    }\n");
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                hadStringOrChain = true;
-                fprintf(out, "    jbyte* jbyte_array%d;\n", argIndex);
-                fprintf(out, "    const char* str%d;\n", argIndex);
-                fprintf(out, "    int str%d_length = 0;\n", argIndex);
-                fprintf(out,
-                        "    if (arg%d != NULL && env->GetArrayLength(arg%d) > "
-                        "0) {\n",
-                        argIndex, argIndex);
-                fprintf(out,
-                        "        jbyte_array%d = "
-                        "env->GetByteArrayElements(arg%d, NULL);\n",
-                        argIndex, argIndex);
-                fprintf(out,
-                        "        str%d_length = env->GetArrayLength(arg%d);\n",
-                        argIndex, argIndex);
-                fprintf(out,
-                        "        str%d = "
-                        "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
-                        "d, NULL));\n",
-                        argIndex, argIndex);
-                fprintf(out, "    } else {\n");
-                fprintf(out, "        jbyte_array%d = NULL;\n", argIndex);
-                fprintf(out, "        str%d = NULL;\n", argIndex);
-                fprintf(out, "    }\n");
-
-                fprintf(out,
-                        "    android::util::BytesField bytesField%d(str%d, "
-                        "str%d_length);",
-                        argIndex, argIndex, argIndex);
-
-            } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                hadStringOrChain = true;
-                for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, "    size_t %s_length = env->GetArrayLength(%s);\n",
-                        chainField.name.c_str(), chainField.name.c_str());
-                    if (chainField.name != attributionDecl.fields.front().name) {
-                        fprintf(out, "    if (%s_length != %s_length) {\n",
-                            chainField.name.c_str(),
-                            attributionDecl.fields.front().name.c_str());
-                        fprintf(out, "        return -EINVAL;\n");
-                        fprintf(out, "    }\n");
-                    }
-                    if (chainField.javaType == JAVA_TYPE_INT) {
-                        fprintf(out, "    jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
-                            chainField.name.c_str(), chainField.name.c_str());
-                    } else if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, "    std::vector<%s> %s_vec;\n",
-                            cpp_type_name(chainField.javaType), chainField.name.c_str());
-                        fprintf(out, "    std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
-                            chainField.name.c_str());
-                        fprintf(out, "    for (size_t i = 0; i < %s_length; ++i) {\n",
-                            chainField.name.c_str());
-                        fprintf(out, "        jstring jstr = "
-                            "(jstring)env->GetObjectArrayElement(%s, i);\n",
-                             chainField.name.c_str());
-                        fprintf(out, "        if (jstr == NULL) {\n");
-                        fprintf(out, "            %s_vec.push_back(NULL);\n",
-                            chainField.name.c_str());
-                        fprintf(out, "        } else {\n");
-                        fprintf(out, "            ScopedUtfChars* scoped_%s = "
-                            "new ScopedUtfChars(env, jstr);\n",
-                             chainField.name.c_str());
-                        fprintf(out, "            %s_vec.push_back(scoped_%s->c_str());\n",
-                                chainField.name.c_str(), chainField.name.c_str());
-                        fprintf(out, "            scoped_%s_vec.push_back(scoped_%s);\n",
-                                chainField.name.c_str(), chainField.name.c_str());
-                        fprintf(out, "        }\n");
-                        fprintf(out, "    }\n");
-                    }
-                    fprintf(out, "\n");
-                }
-            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                isKeyValuePairAtom = true;
-            }
-            argIndex++;
-        }
-        // Emit this to quiet the unused parameter warning if there were no strings or attribution
-        // chains.
-        if (!hadStringOrChain && !isKeyValuePairAtom) {
-            fprintf(out, "    (void)env;\n");
-        }
-        if (isKeyValuePairAtom) {
-            write_key_value_map_jni(out);
-        }
-
-        // stats_write call
-        argIndex = 1;
-        fprintf(out, "\n    int ret =  android::util::%s(code",
-                cpp_method_name.c_str());
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
-            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    if (chainField.javaType == JAVA_TYPE_INT) {
-                        fprintf(out, ", (const %s*)%s_array, %s_length",
-                            cpp_type_name(chainField.javaType),
-                            chainField.name.c_str(), chainField.name.c_str());
-                    } else if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, ", %s_vec", chainField.name.c_str());
-                    }
-                }
-            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out, ", bytesField%d", argIndex);
-            } else {
-                const char* argName =
-                        (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
-                fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
-            }
-            argIndex++;
-        }
-        fprintf(out, ");\n");
-        fprintf(out, "\n");
-
-        // Clean up strings
-        argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
-            if (*arg == JAVA_TYPE_STRING) {
-                fprintf(out, "    if (str%d != NULL) {\n", argIndex);
-                fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
-                        argIndex, argIndex);
-                fprintf(out, "    }\n");
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out, "    if (str%d != NULL) { \n", argIndex);
-                fprintf(out,
-                        "        env->ReleaseByteArrayElements(arg%d, "
-                        "jbyte_array%d, 0);\n",
-                        argIndex, argIndex);
-                fprintf(out, "    }\n");
-            } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
-                    if (chainField.javaType == JAVA_TYPE_INT) {
-                        fprintf(out, "    env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
-                            chainField.name.c_str(), chainField.name.c_str());
-                    } else if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, "    for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
-                            chainField.name.c_str());
-                        fprintf(out, "        delete scoped_%s_vec[i];\n", chainField.name.c_str());
-                        fprintf(out, "    }\n");
-                    }
-                }
-            }
-            argIndex++;
-        }
-
-        fprintf(out, "    return ret;\n");
-
-        fprintf(out, "}\n");
-        fprintf(out, "\n");
-    }
-
-
-    return 0;
-}
-
-void write_jni_registration(FILE* out, const string& java_method_name,
-        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
-        const AtomDecl &attributionDecl) {
-    for (auto signature_to_modules_it = signatures_to_modules.begin();
-            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
-        vector<java_type_t> signature = signature_to_modules_it->first;
-        fprintf(out, "    { \"%s\", \"%s\", (void*)%s },\n",
-            java_method_name.c_str(),
-            jni_function_signature(signature, attributionDecl).c_str(),
-            jni_function_name(java_method_name, signature).c_str());
-    }
-}
-#endif // JNI helpers.
-
-static int
-#if defined(STATS_SCHEMA_LEGACY)
-write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
-#else
-// Write empty JNI file that doesn't contain any JNI methods.
-// TODO(b/145100015): remove this function and all JNI autogen code once StatsEvent migration is
-// complete.
-write_stats_log_jni(FILE* out)
-#endif
-{
-    // Print prelude
-    fprintf(out, "// This file is autogenerated\n");
-    fprintf(out, "\n");
-
-#if defined(STATS_SCHEMA_LEGACY)
-    fprintf(out, "#include <statslog.h>\n");
-    fprintf(out, "\n");
-    fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
-    fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
-    fprintf(out, "#include <utils/Vector.h>\n");
-#endif
-    fprintf(out, "#include \"core_jni_helpers.h\"\n");
-    fprintf(out, "#include \"jni.h\"\n");
-    fprintf(out, "\n");
-#if defined(STATS_SCHEMA_LEGACY)
-    fprintf(out, "#define UNUSED  __attribute__((__unused__))\n");
-    fprintf(out, "\n");
-#endif
-
-    fprintf(out, "namespace android {\n");
-    fprintf(out, "\n");
-
-#if defined(STATS_SCHEMA_LEGACY)
-    write_stats_log_jni_method(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
-    write_stats_log_jni_method(out, "write_non_chained", "stats_write_non_chained",
-            atoms.non_chained_signatures_to_modules, attributionDecl);
-#endif
-
-    // Print registration function table
-    fprintf(out, "/*\n");
-    fprintf(out, " * JNI registration.\n");
-    fprintf(out, " */\n");
-    fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
-#if defined(STATS_SCHEMA_LEGACY)
-    write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
-    write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
-            attributionDecl);
-#endif
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
-
-    // Print registration function
-    fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
-    fprintf(out, "    return RegisterMethodsOrDie(\n");
-    fprintf(out, "            env,\n");
-    fprintf(out, "            \"android/util/StatsLogInternal\",\n");
-    fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
-    fprintf(out, "}\n");
-
-    fprintf(out, "\n");
-    fprintf(out, "} // namespace android\n");
-    return 0;
-}
-
 static void
 print_usage()
 {
@@ -498,7 +38,6 @@
     fprintf(stderr, "  --atomsInfoHeader FILENAME    the cpp file to output for statsd metadata\n");
     fprintf(stderr, "  --help               this message\n");
     fprintf(stderr, "  --java FILENAME      the java file to output\n");
-    fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
     fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
     fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
     fprintf(stderr, "                                    comma separated namespace of the files\n");
@@ -526,16 +65,15 @@
     string cppFilename;
     string headerFilename;
     string javaFilename;
-    string jniFilename;
     string atomsInfoCppFilename;
     string atomsInfoHeaderFilename;
+    string javaPackage;
+    string javaClass;
 
     string moduleName = DEFAULT_MODULE_NAME;
     string cppNamespace = DEFAULT_CPP_NAMESPACE;
     string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
     string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT;
-    string javaPackage = DEFAULT_JAVA_PACKAGE;
-    string javaClass = DEFAULT_JAVA_CLASS;
     bool supportQ = false;
     bool supportWorkSource = false;
     bool compileQ = false;
@@ -566,13 +104,6 @@
                 return 1;
             }
             javaFilename = argv[index];
-        } else if (0 == strcmp("--jni", argv[index])) {
-            index++;
-            if (index >= argc) {
-                print_usage();
-                return 1;
-            }
-            jniFilename = argv[index];
         } else if (0 == strcmp("--module", argv[index])) {
             index++;
             if (index >= argc) {
@@ -643,7 +174,6 @@
     if (cppFilename.size() == 0
             && headerFilename.size() == 0
             && javaFilename.size() == 0
-            && jniFilename.size() == 0
             && atomsInfoHeaderFilename.size() == 0
             && atomsInfoCppFilename.size() == 0) {
         print_usage();
@@ -682,7 +212,7 @@
             return 1;
         }
         errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
-            out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport);
+            out, atoms, cppNamespace, atomsInfoCppHeaderImport);
         fclose(out);
     }
 
@@ -738,27 +268,27 @@
 
     // Write the .java file
     if (javaFilename.size() != 0) {
+        if (javaClass.size() == 0) {
+            fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
+            return 1;
+        }
+
+        if (javaPackage.size() == 0) {
+            fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
+            return 1;
+        }
+
+        if (moduleName.size() == 0) {
+            fprintf(stderr, "Must supply --module if supplying a Java filename");
+            return 1;
+        }
+
         FILE* out = fopen(javaFilename.c_str(), "w");
         if (out == NULL) {
             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
             return 1;
         }
 
-#if defined(STATS_SCHEMA_LEGACY)
-        if (moduleName == DEFAULT_MODULE_NAME) {
-            errorCount = android::stats_log_api_gen::write_stats_log_java_q(
-                    out, atoms, attributionDecl, supportWorkSource);
-        } else {
-            errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
-                    out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
-                    supportWorkSource);
-
-        }
-#else
-        if (moduleName == DEFAULT_MODULE_NAME) {
-            javaClass = "StatsLogInternal";
-            javaPackage = "android.util";
-        }
         if (compileQ) {
             errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
                     out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
@@ -768,25 +298,6 @@
                     out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
                     supportWorkSource);
         }
-#endif
-
-        fclose(out);
-    }
-
-    // Write the jni file
-    if (jniFilename.size() != 0) {
-        FILE* out = fopen(jniFilename.c_str(), "w");
-        if (out == NULL) {
-            fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
-            return 1;
-        }
-
-#if defined(STATS_SCHEMA_LEGACY)
-        errorCount = android::stats_log_api_gen::write_stats_log_jni(
-            out, atoms, attributionDecl);
-#else
-        errorCount = android::stats_log_api_gen::write_stats_log_jni(out);
-#endif
 
         fclose(out);
     }
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 285514d..da207d6 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -15,14 +15,11 @@
  */
 
 #include "native_writer.h"
-#include "native_writer_q.h"
 #include "utils.h"
 
 namespace android {
 namespace stats_log_api_gen {
 
-#if !defined(STATS_SCHEMA_LEGACY)
-
 static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
         const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) {
     fprintf(out, "\n");
@@ -175,7 +172,6 @@
     }
 
 }
-#endif
 
 static void write_native_method_header(
         FILE* out,
@@ -191,12 +187,10 @@
         }
         vector<java_type_t> signature = signature_to_modules_it->first;
 
-#if !defined(STATS_SCHEMA_LEGACY)
         // Key value pairs not supported in native.
         if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
             continue;
         }
-#endif
         write_native_method_signature(out, methodName, signature, attributionDecl, ";");
     }
 }
@@ -209,33 +203,17 @@
     fprintf(out, "\n");
 
     fprintf(out, "#include <%s>\n", importHeader.c_str());
-#if defined(STATS_SCHEMA_LEGACY)
-    (void)supportQ; // Workaround for unused parameter error.
-    write_native_cpp_includes_q(out);
-#else
     if (supportQ) {
         fprintf(out, "#include <StatsEventCompat.h>\n");
     } else {
         fprintf(out, "#include <stats_event.h>\n");
     }
-#endif
 
     fprintf(out, "\n");
     write_namespace(out, cppNamespace);
 
-#if defined(STATS_SCHEMA_LEGACY)
-    write_native_stats_log_cpp_globals_q(out);
-    write_native_get_timestamp_ns_q(out);
-    write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName);
-    write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName,
-            "try_stats_write");
-    write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName);
-    write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms,
-            attributionDecl, moduleName, "try_stats_write_non_chained");
-#else
     write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ);
     write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName);
-#endif
 
     // Print footer
     fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/native_writer_q.cpp b/tools/stats_log_api_gen/native_writer_q.cpp
deleted file mode 100644
index 299873d..0000000
--- a/tools/stats_log_api_gen/native_writer_q.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "native_writer_q.h"
-#include "utils.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature,
-        const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) {
-    fprintf(out, "%sint ret = 0;\n", indent.c_str());
-
-    fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str());
-    fprintf(out, "%s    ret = ", indent.c_str());
-    write_native_method_call(out, tryMethodName, signature, attributionDecl);
-    fprintf(out, "%s    if (ret >= 0) { break; }\n", indent.c_str());
-
-    fprintf(out, "%s    {\n", indent.c_str());
-    fprintf(out, "%s        std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str());
-    fprintf(out, "%s        if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= "
-                            "kMinRetryIntervalNs) break;\n", indent.c_str());
-    fprintf(out, "%s        lastRetryTimestampNs = get_elapsed_realtime_ns();\n",
-            indent.c_str());
-    fprintf(out, "%s    }\n", indent.c_str());
-    fprintf(out, "%s    std::this_thread::sleep_for(std::chrono::milliseconds(10));\n",
-            indent.c_str());
-    fprintf(out, "%s}\n", indent.c_str());
-    fprintf(out, "%sif (ret < 0) {\n", indent.c_str());
-    fprintf(out, "%s    note_log_drop(ret, code);\n", indent.c_str());
-    fprintf(out, "%s}\n", indent.c_str());
-    fprintf(out, "%sreturn ret;\n", indent.c_str());
-}
-
-void write_native_cpp_includes_q(FILE* out) {
-    fprintf(out, "#include <mutex>\n");
-    fprintf(out, "#include <chrono>\n");
-    fprintf(out, "#include <thread>\n");
-    fprintf(out, "#ifdef __ANDROID__\n");
-    fprintf(out, "#include <cutils/properties.h>\n");
-    fprintf(out, "#endif\n");
-    fprintf(out, "#include <stats_event_list.h>\n");
-    fprintf(out, "#include <log/log.h>\n");
-    fprintf(out, "#include <time.h>\n");
-}
-
-void write_native_get_timestamp_ns_q(FILE* out) {
-    fprintf(out, "\n");
-    fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n");
-    fprintf(out, "    struct timespec t;\n");
-    fprintf(out, "    t.tv_sec = t.tv_nsec = 0;\n");
-    fprintf(out, "    clock_gettime(CLOCK_BOOTTIME, &t);\n");
-    fprintf(out, "    return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n");
-    fprintf(out, "}\n");
-}
-
-void write_native_stats_log_cpp_globals_q(FILE* out) {
-    fprintf(out, "// the single event tag id for all stats logs\n");
-    fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
-    fprintf(out, "#ifdef __ANDROID__\n");
-    fprintf(out,
-            "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
-    fprintf(out, "#else\n");
-    fprintf(out, "const static bool kStatsdEnabled = false;\n");
-    fprintf(out, "#endif\n");
-
-    fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
-    fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
-    fprintf(out, "static std::mutex mLogdRetryMutex;\n");
-}
-
-void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const string& moduleName) {
-    fprintf(out, "\n");
-    for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
-        signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
-        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
-            continue;
-        }
-        vector<java_type_t> signature = signature_to_modules_it->first;
-
-        write_native_method_signature(out, "static int try_stats_write", signature,
-                attributionDecl, " {");
-
-        int argIndex = 1;
-        fprintf(out, "  if (kStatsdEnabled) {\n");
-        fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
-        fprintf(out, "    event << get_elapsed_realtime_ns();\n\n");
-        fprintf(out, "    event << code;\n\n");
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-            arg != signature.end(); arg++) {
-            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (const auto &chainField : attributionDecl.fields) {
-                    if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, "    if (%s_length != %s.size()) {\n",
-                            attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
-                        fprintf(out, "        return -EINVAL;\n");
-                        fprintf(out, "    }\n");
-                    }
-                }
-                fprintf(out, "\n    event.begin();\n");
-                fprintf(out, "    for (size_t i = 0; i < %s_length; ++i) {\n",
-                    attributionDecl.fields.front().name.c_str());
-                fprintf(out, "        event.begin();\n");
-                for (const auto &chainField : attributionDecl.fields) {
-                    if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, "        if (%s[i] != NULL) {\n", chainField.name.c_str());
-                        fprintf(out, "           event << %s[i];\n", chainField.name.c_str());
-                        fprintf(out, "        } else {\n");
-                        fprintf(out, "           event << \"\";\n");
-                        fprintf(out, "        }\n");
-                    } else {
-                        fprintf(out, "        event << %s[i];\n", chainField.name.c_str());
-                    }
-                }
-                fprintf(out, "        event.end();\n");
-                fprintf(out, "    }\n");
-                fprintf(out, "    event.end();\n\n");
-            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                    fprintf(out, "    event.begin();\n\n");
-                    fprintf(out, "    for (const auto& it : arg%d_1) {\n", argIndex);
-                    fprintf(out, "         event.begin();\n");
-                    fprintf(out, "         event << it.first;\n");
-                    fprintf(out, "         event << it.second;\n");
-                    fprintf(out, "         event.end();\n");
-                    fprintf(out, "    }\n");
-
-                    fprintf(out, "    for (const auto& it : arg%d_2) {\n", argIndex);
-                    fprintf(out, "         event.begin();\n");
-                    fprintf(out, "         event << it.first;\n");
-                    fprintf(out, "         event << it.second;\n");
-                    fprintf(out, "         event.end();\n");
-                    fprintf(out, "    }\n");
-
-                    fprintf(out, "    for (const auto& it : arg%d_3) {\n", argIndex);
-                    fprintf(out, "         event.begin();\n");
-                    fprintf(out, "         event << it.first;\n");
-                    fprintf(out, "         event << it.second;\n");
-                    fprintf(out, "         event.end();\n");
-                    fprintf(out, "    }\n");
-
-                    fprintf(out, "    for (const auto& it : arg%d_4) {\n", argIndex);
-                    fprintf(out, "         event.begin();\n");
-                    fprintf(out, "         event << it.first;\n");
-                    fprintf(out, "         event << it.second;\n");
-                    fprintf(out, "         event.end();\n");
-                    fprintf(out, "    }\n");
-
-                    fprintf(out, "    event.end();\n\n");
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out,
-                        "    event.AppendCharArray(arg%d.arg, "
-                        "arg%d.arg_length);\n",
-                        argIndex, argIndex);
-            } else {
-                if (*arg == JAVA_TYPE_STRING) {
-                    fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
-                    fprintf(out, "        arg%d = \"\";\n", argIndex);
-                    fprintf(out, "    }\n");
-                }
-                fprintf(out, "    event << arg%d;\n", argIndex);
-            }
-            argIndex++;
-        }
-
-        fprintf(out, "    return event.write(LOG_ID_STATS);\n");
-        fprintf(out, "  } else {\n");
-        fprintf(out, "    return 1;\n");
-        fprintf(out, "  }\n");
-        fprintf(out, "}\n");
-        fprintf(out, "\n");
-    }
-
-}
-
-void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) {
-    for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
-        signature_to_modules_it != atoms.signatures_to_modules.end();
-        signature_to_modules_it++) {
-        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
-            continue;
-        }
-        vector<java_type_t> signature = signature_to_modules_it->first;
-
-        write_native_method_signature(out, methodName, signature, attributionDecl, " {");
-
-        write_native_stats_write_body_q(out, signature, attributionDecl, "    ", tryMethodName);
-        fprintf(out, "}\n\n");
-    }
-}
-
-void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
-        const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
-        const string& tryMethodName) {
-    for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
-            signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
-        if (!signature_needed_for_module(signature_it->second, moduleName)) {
-            continue;
-        }
-        vector<java_type_t> signature = signature_it->first;
-
-        write_native_method_signature(out, methodName, signature, attributionDecl, " {");
-
-        write_native_stats_write_body_q(out, signature, attributionDecl, "    ", tryMethodName);
-        fprintf(out, "}\n\n");
-    }
-}
-
-void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const string& moduleName) {
-    for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
-            signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
-        if (!signature_needed_for_module(signature_it->second, moduleName)) {
-            continue;
-        }
-        vector<java_type_t> signature = signature_it->first;
-
-        write_native_method_signature(out, "static int try_stats_write_non_chained", signature,
-                attributionDecl, " {");
-
-        int argIndex = 1;
-        fprintf(out, "  if (kStatsdEnabled) {\n");
-        fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
-        fprintf(out, "    event << get_elapsed_realtime_ns();\n\n");
-        fprintf(out, "    event << code;\n\n");
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-            arg != signature.end(); arg++) {
-            if (argIndex == 1) {
-                fprintf(out, "    event.begin();\n\n");
-                fprintf(out, "    event.begin();\n");
-            }
-            if (*arg == JAVA_TYPE_STRING) {
-                fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
-                fprintf(out, "        arg%d = \"\";\n", argIndex);
-                fprintf(out, "    }\n");
-            }
-            if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out,
-                        "    event.AppendCharArray(arg%d.arg, "
-                        "arg%d.arg_length);\n",
-                        argIndex, argIndex);
-            } else {
-                fprintf(out, "    event << arg%d;\n", argIndex);
-            }
-            if (argIndex == 2) {
-                fprintf(out, "    event.end();\n\n");
-                fprintf(out, "    event.end();\n\n");
-            }
-            argIndex++;
-        }
-
-        fprintf(out, "    return event.write(LOG_ID_STATS);\n");
-        fprintf(out, "  } else {\n");
-        fprintf(out, "    return 1;\n");
-        fprintf(out, "  }\n");
-        fprintf(out, "}\n");
-        fprintf(out, "\n");
-    }
-}
-
-}  // namespace stats_log_api_gen
-}  // namespace android
diff --git a/tools/stats_log_api_gen/native_writer_q.h b/tools/stats_log_api_gen/native_writer_q.h
deleted file mode 100644
index a2ab1ae..0000000
--- a/tools/stats_log_api_gen/native_writer_q.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Collation.h"
-
-#include <stdio.h>
-#include <string.h>
-
-namespace android {
-namespace stats_log_api_gen {
-
-using namespace std;
-
-void write_native_cpp_includes_q(FILE* out);
-
-void write_native_stats_log_cpp_globals_q(FILE* out);
-
-void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const string& moduleName);
-
-void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName);
-
-void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const string& moduleName);
-
-void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
-        const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
-        const string& tryMethodName);
-
-void write_native_get_timestamp_ns_q(FILE* out);
-
-}  // namespace stats_log_api_gen
-}  // namespace android
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index b892194..f6c89c2 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -41,21 +41,20 @@
 
 message AllTypesAtom {
   repeated android.os.statsd.AttributionNode attribution_chain = 1;
-  optional double double_field = 2;
-  optional float float_field = 3;
-  optional int64 int64_field = 4;
-  optional uint64 uint64_field = 5;
-  optional int32 int32_field = 6;
-  optional fixed64 fixed64_field = 7;
-  optional fixed32 fixed32_field = 8;
-  optional bool bool_field = 9;
-  optional string string_field = 10;
-  optional uint32 uint32_field = 11;
-  optional AnEnum enum_field = 12;
-  optional sfixed32 sfixed32_field = 13;
-  optional sfixed64 sfixed64_field = 14;
-  optional sint32 sint32_field = 15;
-  optional sint64 sint64_field = 16;
+  optional float float_field = 2;
+  optional int64 int64_field = 3;
+  optional uint64 uint64_field = 4;
+  optional int32 int32_field = 5;
+  optional fixed64 fixed64_field = 6;
+  optional fixed32 fixed32_field = 7;
+  optional bool bool_field = 8;
+  optional string string_field = 9;
+  optional uint32 uint32_field = 10;
+  optional AnEnum enum_field = 11;
+  optional sfixed32 sfixed32_field = 12;
+  optional sfixed64 sfixed64_field = 13;
+  optional sint32 sint32_field = 14;
+  optional sint64 sint64_field = 15;
 }
 
 message Event {
@@ -70,6 +69,8 @@
 message BadTypesAtom {
     optional IntAtom bad_int_atom = 1;
     optional bytes bad_bytes = 2;
+    repeated int32 repeated_field = 3;
+    optional double double_field = 4;
 }
 
 message BadTypesEvent {
@@ -212,6 +213,10 @@
     optional int32 field = 1;
 }
 
+message ModuleOneAndTwoAtom {
+    optional int32 field = 1;
+}
+
 message NoModuleAtom {
     optional string field = 1;
 }
@@ -220,6 +225,9 @@
     oneof event {
         ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
         ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
-        NoModuleAtom no_module_atom = 3;
+        ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
+                (android.os.statsd.module) = "module1", (android.os.statsd.module) = "module2"
+        ];
+        NoModuleAtom no_module_atom = 4;
     }
 }
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index bcf18ae..73abaef 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -98,7 +98,6 @@
     EXPECT_SET_CONTAINS_SIGNATURE(
         atoms.signatures_to_modules,
         JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
-        JAVA_TYPE_DOUBLE,            // double
         JAVA_TYPE_FLOAT,             // float
         JAVA_TYPE_LONG,              // int64
         JAVA_TYPE_LONG,              // uint64
@@ -157,13 +156,13 @@
 }
 
 /**
- * Test that atoms that have non-primitive types are rejected.
+ * Test that atoms that have non-primitive types or repeated fields are rejected.
  */
 TEST(CollationTest, FailOnBadTypes) {
     Atoms atoms;
     int errorCount = collate_atoms(BadTypesEvent::descriptor(), &atoms);
 
-    EXPECT_EQ(2, errorCount);
+    EXPECT_EQ(4, errorCount);
 }
 
 /**
@@ -249,23 +248,27 @@
     Atoms atoms;
     int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
     EXPECT_EQ(errorCount, 0);
-    EXPECT_EQ(atoms.decls.size(), 3ul);
+    EXPECT_EQ(atoms.decls.size(), 4ul);
 }
 
 TEST(CollationTest, RecognizeModuleAtom) {
     Atoms atoms;
     int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
     EXPECT_EQ(errorCount, 0);
-    EXPECT_EQ(atoms.decls.size(), 3ul);
+    EXPECT_EQ(atoms.decls.size(), 4ul);
     for (const auto& atomDecl: atoms.decls) {
         if (atomDecl.code == 1) {
-            EXPECT_TRUE(atomDecl.hasModule);
-            EXPECT_EQ(atomDecl.moduleName, "module1");
+            EXPECT_EQ(1ul, atomDecl.moduleNames.size());
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module1"));
         } else if (atomDecl.code == 2) {
-            EXPECT_TRUE(atomDecl.hasModule);
-            EXPECT_EQ(atomDecl.moduleName, "module2");
+            EXPECT_EQ(1ul, atomDecl.moduleNames.size());
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module2"));
+        } else if (atomDecl.code == 3) {
+            EXPECT_EQ(2ul, atomDecl.moduleNames.size());
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module1"));
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module2"));
         } else {
-            EXPECT_FALSE(atomDecl.hasModule);
+            EXPECT_TRUE(atomDecl.moduleNames.empty());
         }
     }
 
@@ -287,4 +290,4 @@
 }
 
 }  // namespace stats_log_api_gen
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 8c4abe4..9dc4ff8 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -102,7 +102,7 @@
     if (moduleName == DEFAULT_MODULE_NAME) {
         return true;
     }
-    return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
+    return atomDecl.moduleNames.find(moduleName) != atomDecl.moduleNames.end();
 }
 
 bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
@@ -286,9 +286,6 @@
         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
             write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
         }
-        if (moduleName == DEFAULT_MODULE_NAME) {
-            fprintf(out, "     * @hide\n");
-        }
         fprintf(out, "     */\n");
         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
     }
@@ -310,9 +307,6 @@
                     field->name.c_str());
                 for (map<int, string>::const_iterator value = field->enumValues.begin();
                     value != field->enumValues.end(); value++) {
-                    if (moduleName == DEFAULT_MODULE_NAME) {
-                        fprintf(out, "    /** @hide */\n");
-                    }
                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
                         make_constant_name(atom->message).c_str(),
                         make_constant_name(field->name).c_str(),
@@ -357,9 +351,6 @@
         }
 
         // Print method signature.
-        if (DEFAULT_MODULE_NAME == moduleName) {
-            fprintf(out, "    /** @hide */\n");
-        }
         fprintf(out, "    public static void write_non_chained(int code");
         vector<java_type_t> signature = signature_to_modules_it->first;
         int argIndex = 1;
@@ -434,9 +425,6 @@
 
         fprintf(out, "\n");
         // Method header (signature)
-        if (DEFAULT_MODULE_NAME == moduleName) {
-            fprintf(out, "    /** @hide */\n");
-        }
         fprintf(out, "    public static void write(int code");
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature.begin();
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index cd602e5..715d42bc 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -34,8 +34,6 @@
 const string DEFAULT_CPP_NAMESPACE = "android,util";
 const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
 const string DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT = "atoms_info.h";
-const string DEFAULT_JAVA_PACKAGE = "android.util";
-const string DEFAULT_JAVA_CLASS = "StatsLogInternal";
 
 const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
 const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index 8ccf007..de2f5d9 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -242,6 +242,8 @@
      *                         to scan to find the network, see the "DPP Connection Status Object"
      *                         section in the specification for the format, and Table E-4 in
      *                         IEEE Std 802.11-2016 - Global operating classes for more details.
+     *                         The sparse array key is the Global Operating class, and the value
+     *                         is an integer array of Wi-Fi channels.
      * @param operatingClassArray Array of bands the Enrollee supports as expressed as the Global
      *                            Operating Class, see Table E-4 in IEEE Std 802.11-2016 - Global
      *                            operating classes.